diff --git a/.upgradenotes/MDL-82212-2024080916163806.yml b/.upgradenotes/MDL-82212-2024080916163806.yml
new file mode 100644
index 00000000000..57d4007f167
--- /dev/null
+++ b/.upgradenotes/MDL-82212-2024080916163806.yml
@@ -0,0 +1,11 @@
+issueNumber: MDL-82212
+notes:
+  core:
+    - message: >-
+        A new method, get_deprecated_icons(), has been added to the icon_system
+        class. All deprecated icons should be registered through this method.
+        Plugins can implement a callback to pluginname_get_deprecated_icons() to
+        register their deprecated icons too.
+        When $CFG->debugpageinfo is enabled, a console message will display a
+        list of the deprecated icons.
+      type: improved
diff --git a/.upgradenotes/MDL-82212-2024081207484596.yml b/.upgradenotes/MDL-82212-2024081207484596.yml
new file mode 100644
index 00000000000..838096c78f1
--- /dev/null
+++ b/.upgradenotes/MDL-82212-2024081207484596.yml
@@ -0,0 +1,7 @@
+issueNumber: MDL-82212
+notes:
+  tool_behat:
+    - message: >-
+        Behat tests are now checking for deprecated icons. This check can be
+        disabled by using the --no-icon-deprecations option in the behat CLI.
+      type: improved
diff --git a/admin/tool/behat/cli/init.php b/admin/tool/behat/cli/init.php
index 87f77742605..26f58a5c270 100644
--- a/admin/tool/behat/cli/init.php
+++ b/admin/tool/behat/cli/init.php
@@ -54,6 +54,7 @@ list($options, $unrecognized) = cli_get_params(
         'composer-upgrade' => true,
         'composer-self-update' => true,
         'scss-deprecations' => false,
+        'no-icon-deprecations' => false,
     ),
     array(
         'j' => 'parallel',
@@ -70,18 +71,20 @@ Behat utilities to initialise behat tests
 
 Usage:
   php init.php      [--parallel=value [--maxruns=value] [--fromrun=value --torun=value]]
-                    [--no-axe] [--scss-deprecations] [-o | --optimize-runs] [-a | --add-core-features-to-theme]
+                    [--no-axe] [--scss-deprecations] [--no-icon-deprecations] [-o | --optimize-runs]
+                    [-a | --add-core-features-to-theme]
                     [--no-composer-self-update] [--no-composer-upgrade]
                     [--disable-composer]
                     [--help]
 
 Options:
--j, --parallel      Number of parallel behat run to initialise
--m, --maxruns       Max parallel processes to be executed at one time
---fromrun           Execute run starting from (Used for parallel runs on different vms)
---torun             Execute run till (Used for parallel runs on different vms)
---no-axe            Disable axe accessibility tests.
---scss-deprecations Enable SCSS deprecation checks.
+-j, --parallel         Number of parallel behat run to initialise
+-m, --maxruns          Max parallel processes to be executed at one time
+--fromrun              Execute run starting from (Used for parallel runs on different vms)
+--torun                Execute run till (Used for parallel runs on different vms)
+--no-axe               Disable axe accessibility tests.
+--scss-deprecations    Enable SCSS deprecation checks.
+--no-icon-deprecations Disable icon deprecation checks.
 
 -o, --optimize-runs
                     Split features with specified tags in all parallel runs.
@@ -134,6 +137,7 @@ if ($options['parallel'] && $options['parallel'] > 1) {
         'add-core-features-to-theme',
         'axe',
         'scss-deprecations',
+        'no-icon-deprecations',
     ];
 
     foreach ($cmdoptionsforsinglerun as $option) {
diff --git a/admin/tool/behat/cli/util.php b/admin/tool/behat/cli/util.php
index 7d36ffa611c..0a65b4e0a2b 100644
--- a/admin/tool/behat/cli/util.php
+++ b/admin/tool/behat/cli/util.php
@@ -59,6 +59,7 @@ list($options, $unrecognized) = cli_get_params(
         'add-core-features-to-theme' => false,
         'axe'         => true,
         'scss-deprecations' => false,
+        'no-icon-deprecations' => false,
     ),
     array(
         'h' => 'help',
@@ -74,18 +75,20 @@ $help = "
 Behat utilities to manage the test environment
 
 Usage:
-  php util.php  [--install|--drop|--enable|--disable|--diag|--updatesteps|--no-axe|--scss-deprecations|--help]
+  php util.php  [--install|--drop|--enable|--disable|--diag|--updatesteps]
+                [--no-axe|--scss-deprecations|--no-icon-deprecations|--help]
                 [--parallel=value [--maxruns=value]]
 
 Options:
---install           Installs the test environment for acceptance tests
---drop              Drops the database tables and the dataroot contents
---enable            Enables test environment and updates tests list
---disable           Disables test environment
---diag              Get behat test environment status code
---updatesteps       Update feature step file.
---no-axe            Disable axe accessibility tests.
---scss-deprecations Enable SCSS deprecation checks.
+--install              Installs the test environment for acceptance tests
+--drop                 Drops the database tables and the dataroot contents
+--enable               Enables test environment and updates tests list
+--disable              Disables test environment
+--diag                 Get behat test environment status code
+--updatesteps          Update feature step file.
+--no-axe               Disable axe accessibility tests.
+--scss-deprecations    Enable SCSS deprecation checks.
+--no-icon-deprecations Disable icon deprecation checks.
 
 -j, --parallel Number of parallel behat run operation
 -m, --maxruns Max parallel processes to be executed at one time.
diff --git a/admin/tool/behat/cli/util_single_run.php b/admin/tool/behat/cli/util_single_run.php
index 942a6f834f5..20ef49f1322 100644
--- a/admin/tool/behat/cli/util_single_run.php
+++ b/admin/tool/behat/cli/util_single_run.php
@@ -54,6 +54,7 @@ list($options, $unrecognized) = cli_get_params(
         'add-core-features-to-theme' => false,
         'axe'         => true,
         'scss-deprecations' => false,
+        'no-icon-deprecations' => false,
     ),
     array(
         'h' => 'help',
@@ -74,14 +75,15 @@ Usage:
   php util_single_run.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--help]
 
 Options:
---install           Installs the test environment for acceptance tests
---drop              Drops the database tables and the dataroot contents
---enable            Enables test environment and updates tests list
---disable           Disables test environment
---diag              Get behat test environment status code
---updatesteps       Update feature step file.
---no-axe            Disable axe accessibility tests.
---scss-deprecations Enable SCSS deprecation checks.
+--install              Installs the test environment for acceptance tests
+--drop                 Drops the database tables and the dataroot contents
+--enable               Enables test environment and updates tests list
+--disable              Disables test environment
+--diag                 Get behat test environment status code
+--updatesteps          Update feature step file.
+--no-axe               Disable axe accessibility tests.
+--scss-deprecations    Enable SCSS deprecation checks.
+--no-icon-deprecations Disable icon deprecation checks.
 
 -o, --optimize-runs Split features with specified tags in all parallel runs.
 -a, --add-core-features-to-theme Add all core features to specified theme's
@@ -194,6 +196,9 @@ if ($options['install']) {
     // Define whether to run Behat with SCSS deprecation checks.
     behat_config_manager::set_behat_run_config_value('scss-deprecations', $options['scss-deprecations']);
 
+    // Define whether to run Behat with icon deprecation checks.
+    behat_config_manager::set_behat_run_config_value('no-icon-deprecations', $options['no-icon-deprecations']);
+
     // Enable test mode.
     $timestart = microtime(true);
     mtrace('Creating Behat configuration ...', '');
diff --git a/lib/behat/classes/behat_session_trait.php b/lib/behat/classes/behat_session_trait.php
index 6d324ecfb3f..7ec03499b40 100644
--- a/lib/behat/classes/behat_session_trait.php
+++ b/lib/behat/classes/behat_session_trait.php
@@ -1049,6 +1049,39 @@ EOF;
         }
     }
 
+
+    /**
+     * Internal step definition to find deprecated icons.
+     *
+     * Part of behat_hooks class as is part of the testing framework, is auto-executed
+     * after each step so no features will splicitly use it.
+     *
+     * @throws Exception Unknown type, depending on what we caught in the hook or basic \Exception.
+     * @see Moodle\BehatExtension\Tester\MoodleStepTester
+     */
+    public function look_for_deprecated_icons() {
+        if (behat_config_manager::get_behat_run_config_value('no-icon-deprecations')) {
+            return;
+        }
+
+        if (!$this->running_javascript()) {
+            return;
+        }
+
+        // Look for any DOM element with deprecated icon.
+        $js = <<<EOF
+            [...document.querySelectorAll('.icon.deprecated')].some(
+                deprecatedicon => true
+            );
+        EOF;
+        if ($this->evaluate_script($js)) {
+            throw new \Exception(html_entity_decode(
+                "Deprecated icon in use. Enable \$CFG->debugdisplay for detailed debugging information in the console",
+                ENT_COMPAT,
+            ));
+        }
+    }
+
     /**
      * Converts HTML tags to line breaks to display the info in CLI
      *
@@ -1090,6 +1123,9 @@ EOF;
 
         // Look for deprecated styles.
         $this->look_for_deprecated_styles();
+
+        // Look for deprecated icons.
+        $this->look_for_deprecated_icons();
     }
 
     /**
diff --git a/lib/behat/classes/util.php b/lib/behat/classes/util.php
index 25d9bfb7db6..2ea60f255d9 100644
--- a/lib/behat/classes/util.php
+++ b/lib/behat/classes/util.php
@@ -519,11 +519,13 @@ class behat_util extends testing_util {
 
         $accessibility = empty(behat_config_manager::get_behat_run_config_value('axe')) ? 'No' : 'Yes';
         $scssdeprecations = empty(behat_config_manager::get_behat_run_config_value('scss-deprecations')) ? 'No' : 'Yes';
+        $icondeprecations = empty(behat_config_manager::get_behat_run_config_value('no-icon-deprecations')) ? 'Yes' : 'No';
 
         $siteinfo .= <<<EOF
 Run optional tests:
 - Accessibility: {$accessibility}
 - SCSS deprecations: {$scssdeprecations}
+- Icon deprecations: {$icondeprecations}
 
 EOF;
 
diff --git a/lib/classes/output/icon_system.php b/lib/classes/output/icon_system.php
index c9f6b5a1488..087e6bbd7c6 100644
--- a/lib/classes/output/icon_system.php
+++ b/lib/classes/output/icon_system.php
@@ -147,4 +147,26 @@ abstract class icon_system {
     public static function reset_caches() {
         self::$instance = null;
     }
+
+    /**
+     * Overridable function to get the list of deprecated icons.
+     *
+     * @return array with the deprecated key icons (for instance, core:a/download_all).
+     */
+    public function get_deprecated_icons(): array {
+        $deprecated = [];
+        // Include deprecated icons in plugins too.
+        $callback = 'get_deprecated_icons';
+
+        if ($pluginsfunction = get_plugins_with_function($callback)) {
+            foreach ($pluginsfunction as $plugintype => $plugins) {
+                foreach ($plugins as $pluginfunction) {
+                    $plugindeprecated = $pluginfunction();
+                    $deprecated += $plugindeprecated;
+                }
+            }
+        }
+
+        return $deprecated;
+    }
 }
diff --git a/lib/classes/output/icon_system_fontawesome.php b/lib/classes/output/icon_system_fontawesome.php
index 400102b5929..c59787e04c2 100644
--- a/lib/classes/output/icon_system_fontawesome.php
+++ b/lib/classes/output/icon_system_fontawesome.php
@@ -488,9 +488,14 @@ class icon_system_fontawesome extends icon_system_font {
                     }
                 }
 
-                // Add the solid class by default to all icons that have not specific family.
+                $deprecated = $this->get_deprecated_icons();
                 foreach ($this->map as $from => $to) {
+                    // Add the solid class by default to all icons that have not specific family.
                     $this->map[$from] = $this->add_family($to);
+                    // Add the deprecated class to all deprecated icons.
+                    if (in_array($from, $deprecated)) {
+                        $this->map[$from] .= ' deprecated deprecated-'.$from;
+                    }
                 }
 
                 $cache->set($mapkey, $this->map);
@@ -528,6 +533,15 @@ class icon_system_fontawesome extends icon_system_font {
 
         if (!$subpix->is_mapped()) {
             $data['unmappedIcon'] = $icon->export_for_template($output);
+            // If the icon is not mapped, we need to check if it is deprecated.
+            $component = $icon->component;
+            if (empty($component) || $component === 'moodle' || $component === 'core') {
+                $component = 'core';
+            }
+            $iconname = $component . ':' . $icon->pix;
+            if (in_array($iconname, $this->get_deprecated_icons())) {
+                $data['unmappedIcon']['extraclasses'] .= ' deprecated deprecated-'.$iconname;
+            }
         }
         if (isset($icon->attributes['aria-hidden'])) {
             $data['aria-hidden'] = $icon->attributes['aria-hidden'];
diff --git a/lib/pagelib.php b/lib/pagelib.php
index 15f81510a16..5b32c4d13e7 100644
--- a/lib/pagelib.php
+++ b/lib/pagelib.php
@@ -1097,6 +1097,18 @@ class moodle_page {
         if ($this->subpage) {
             $summary .= 'Sub-page ' . $this->subpage .  '. ';
         }
+
+        // Display deprecated icons in the console (if any).
+        $summary .= <<< EOF
+            <script type="text/javascript">
+            //<![CDATA[
+            document.querySelectorAll('.icon.deprecated').forEach((icon) => {
+                window.console.warn("Deprecated icon found: " + icon.className);
+            });
+            //]]>
+            </script>
+        EOF;
+
         return $summary;
     }