diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md
index 9ae74fb1..6f0f3518 100644
--- a/docs/about/release-notes.md
+++ b/docs/about/release-notes.md
@@ -66,6 +66,7 @@ authors should review how [search and themes] interact.
 
 ### Other Changes and Additions to Development Version
 
+* Improve Markdown extension error messages. (#782).
 * Drop official support for Python 3.3 and set `tornado>=5.0` (#1427).
 * Add support for GitLab edit links (#1435).
 * Link to GitHub issues from release notes (#644).
diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py
index 30da2a2a..a67dd05e 100644
--- a/mkdocs/config/config_options.py
+++ b/mkdocs/config/config_options.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
 from collections import Sequence
 import os
 from collections import namedtuple
+import markdown
 
 from mkdocs import utils, theme, plugins
 from mkdocs.config.base import Config, ValidationError
@@ -629,7 +630,16 @@ class MarkdownExtensions(OptionallyRequired):
                 extensions.append(item)
             else:
                 raise ValidationError('Invalid Markdown Extensions configuration')
-        return utils.reduce_list(self.builtins + extensions)
+
+        extensions = utils.reduce_list(self.builtins + extensions)
+
+        # Confirm that Markdown considers extensions to be valid
+        try:
+            markdown.Markdown(extensions=extensions, extension_configs=self.configdata)
+        except Exception as e:
+            raise ValidationError(e.args[0])
+
+        return extensions
 
     def post_validation(self, config, key_name):
         config[self.configkey] = self.configdata
diff --git a/requirements/project-min.txt b/requirements/project-min.txt
index 6b0262e0..a60bec24 100644
--- a/requirements/project-min.txt
+++ b/requirements/project-min.txt
@@ -4,3 +4,4 @@ livereload==2.5.1
 Markdown==2.5
 PyYAML==3.10
 tornado==4.1
+mdx_gh_links>=0.2

Improve error message for missing Markdown extensions
I just had to install that manually.

diff --git a/mkdocs/tests/cli_tests.py b/mkdocs/tests/cli_tests.py
index 85ab87de..57f12845 100644
--- a/mkdocs/tests/cli_tests.py
+++ b/mkdocs/tests/cli_tests.py
@@ -186,8 +186,9 @@ class CLITests(unittest.TestCase):
         logger = logging.getLogger('mkdocs')
         self.assertEqual(logger.level, logging.INFO)
 
+    @mock.patch('mkdocs.config.load_config', autospec=True)
     @mock.patch('mkdocs.commands.build.build', autospec=True)
-    def test_build_clean(self, mock_build):
+    def test_build_clean(self, mock_build, mock_load_config):
 
         result = self.runner.invoke(
             cli.cli, ['build', '--clean'], catch_exceptions=False)
@@ -198,8 +199,9 @@ class CLITests(unittest.TestCase):
         self.assertTrue('dirty' in kwargs)
         self.assertFalse(kwargs['dirty'])
 
+    @mock.patch('mkdocs.config.load_config', autospec=True)
     @mock.patch('mkdocs.commands.build.build', autospec=True)
-    def test_build_dirty(self, mock_build):
+    def test_build_dirty(self, mock_build, mock_load_config):
 
         result = self.runner.invoke(
             cli.cli, ['build', '--dirty'], catch_exceptions=False)
@@ -296,8 +298,9 @@ class CLITests(unittest.TestCase):
             site_dir='custom'
         )
 
+    @mock.patch('mkdocs.config.load_config', autospec=True)
     @mock.patch('mkdocs.commands.build.build', autospec=True)
-    def test_build_verbose(self, mock_build):
+    def test_build_verbose(self, mock_build, mock_load_config):
 
         result = self.runner.invoke(
             cli.cli, ['build', '--verbose'], catch_exceptions=False)
@@ -307,8 +310,9 @@ class CLITests(unittest.TestCase):
         logger = logging.getLogger('mkdocs')
         self.assertEqual(logger.level, logging.DEBUG)
 
+    @mock.patch('mkdocs.config.load_config', autospec=True)
     @mock.patch('mkdocs.commands.build.build', autospec=True)
-    def test_build_quiet(self, mock_build):
+    def test_build_quiet(self, mock_build, mock_load_config):
 
         result = self.runner.invoke(
             cli.cli, ['build', '--quiet'], catch_exceptions=False)
@@ -352,9 +356,10 @@ class CLITests(unittest.TestCase):
             remote_name=None
         )
 
+    @mock.patch('mkdocs.config.load_config', autospec=True)
     @mock.patch('mkdocs.commands.build.build', autospec=True)
     @mock.patch('mkdocs.commands.gh_deploy.gh_deploy', autospec=True)
-    def test_gh_deploy_clean(self, mock_gh_deploy, mock_build):
+    def test_gh_deploy_clean(self, mock_gh_deploy, mock_build, mock_load_config):
 
         result = self.runner.invoke(
             cli.cli, ['gh-deploy', '--clean'], catch_exceptions=False)
@@ -366,9 +371,10 @@ class CLITests(unittest.TestCase):
         self.assertTrue('dirty' in kwargs)
         self.assertFalse(kwargs['dirty'])
 
+    @mock.patch('mkdocs.config.load_config', autospec=True)
     @mock.patch('mkdocs.commands.build.build', autospec=True)
     @mock.patch('mkdocs.commands.gh_deploy.gh_deploy', autospec=True)
-    def test_gh_deploy_dirty(self, mock_gh_deploy, mock_build):
+    def test_gh_deploy_dirty(self, mock_gh_deploy, mock_build, mock_load_config):
 
         result = self.runner.invoke(
             cli.cli, ['gh-deploy', '--dirty'], catch_exceptions=False)
diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py
index 56b7a724..1d573ba2 100644
--- a/mkdocs/tests/config/config_options_tests.py
+++ b/mkdocs/tests/config/config_options_tests.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 import os
 import unittest
+from mock import patch
 
 import mkdocs
 from mkdocs import utils
@@ -491,7 +492,8 @@ class PrivateTest(unittest.TestCase):
 
 class MarkdownExtensionsTest(unittest.TestCase):
 
-    def test_simple_list(self):
+    @patch('markdown.Markdown')
+    def test_simple_list(self, mockMd):
         option = config_options.MarkdownExtensions()
         config = {
             'markdown_extensions': ['foo', 'bar']
@@ -503,7 +505,8 @@ class MarkdownExtensionsTest(unittest.TestCase):
             'mdx_configs': {}
         }, config)
 
-    def test_list_dicts(self):
+    @patch('markdown.Markdown')
+    def test_list_dicts(self, mockMd):
         option = config_options.MarkdownExtensions()
         config = {
             'markdown_extensions': [
@@ -522,7 +525,8 @@ class MarkdownExtensionsTest(unittest.TestCase):
             }
         }, config)
 
-    def test_mixed_list(self):
+    @patch('markdown.Markdown')
+    def test_mixed_list(self, mockMd):
         option = config_options.MarkdownExtensions()
         config = {
             'markdown_extensions': [
@@ -539,7 +543,8 @@ class MarkdownExtensionsTest(unittest.TestCase):
             }
         }, config)
 
-    def test_builtins(self):
+    @patch('markdown.Markdown')
+    def test_builtins(self, mockMd):
         option = config_options.MarkdownExtensions(builtins=['meta', 'toc'])
         config = {
             'markdown_extensions': ['foo', 'bar']
@@ -577,7 +582,8 @@ class MarkdownExtensionsTest(unittest.TestCase):
             'mdx_configs': {'toc': {'permalink': True}}
         }, config)
 
-    def test_configkey(self):
+    @patch('markdown.Markdown')
+    def test_configkey(self, mockMd):
         option = config_options.MarkdownExtensions(configkey='bar')
         config = {
             'markdown_extensions': [
@@ -605,12 +611,14 @@ class MarkdownExtensionsTest(unittest.TestCase):
             'mdx_configs': {}
         }, config)
 
-    def test_not_list(self):
+    @patch('markdown.Markdown')
+    def test_not_list(self, mockMd):
         option = config_options.MarkdownExtensions()
         self.assertRaises(config_options.ValidationError,
                           option.validate, 'not a list')
 
-    def test_invalid_config_option(self):
+    @patch('markdown.Markdown')
+    def test_invalid_config_option(self, mockMd):
         option = config_options.MarkdownExtensions()
         config = {
             'markdown_extensions': [
@@ -622,7 +630,8 @@ class MarkdownExtensionsTest(unittest.TestCase):
             option.validate, config['markdown_extensions']
         )
 
-    def test_invalid_config_item(self):
+    @patch('markdown.Markdown')
+    def test_invalid_config_item(self, mockMd):
         option = config_options.MarkdownExtensions()
         config = {
             'markdown_extensions': [
@@ -634,7 +643,8 @@ class MarkdownExtensionsTest(unittest.TestCase):
             option.validate, config['markdown_extensions']
         )
 
-    def test_invalid_dict_item(self):
+    @patch('markdown.Markdown')
+    def test_invalid_dict_item(self, mockMd):
         option = config_options.MarkdownExtensions()
         config = {
             'markdown_extensions': [
@@ -645,3 +655,13 @@ class MarkdownExtensionsTest(unittest.TestCase):
             config_options.ValidationError,
             option.validate, config['markdown_extensions']
         )
+
+    def test_unknown_extension(self):
+        option = config_options.MarkdownExtensions()
+        config = {
+            'markdown_extensions': ['unknown']
+        }
+        self.assertRaises(
+            config_options.ValidationError,
+            option.validate, config['markdown_extensions']
+        )
diff --git a/mkdocs/tests/gh_deploy_tests.py b/mkdocs/tests/gh_deploy_tests.py
index b08e28df..d12f98cc 100644
--- a/mkdocs/tests/gh_deploy_tests.py
+++ b/mkdocs/tests/gh_deploy_tests.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import unittest
 import mock
 
-from mkdocs.config import load_config
+from mkdocs.tests.base import load_config
 from mkdocs.commands import gh_deploy
 
 

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-mock mock
apt-get update apt-get install -y gcc
3.9
requirements/project.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
click==8.1.8
exceptiongroup==1.2.2
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
livereload==2.7.1
Markdown==3.7
MarkupSafe==3.0.2
mdx-gh-links==0.4
-e git+https://github.com/mkdocs/mkdocs.git@d4c5832876accc7e59293852d86810585b97674c#egg=mkdocs
mock==5.2.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
pytest-mock==3.14.0
PyYAML==6.0.2
tomli==2.2.1
tornado==6.4.2
zipp==3.21.0

name: mkdocs
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - click==8.1.8
      - exceptiongroup==1.2.2
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - livereload==2.7.1
      - markdown==3.7
      - markupsafe==3.0.2
      - mdx-gh-links==0.4
      - mock==5.2.0
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-mock==3.14.0
      - pyyaml==6.0.2
      - tomli==2.2.1
      - tornado==6.4.2
      - zipp==3.21.0
prefix: /opt/conda/envs/mkdocs

mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_unknown_extension
mkdocs/tests/cli_tests.py::CLITests::test_build_clean mkdocs/tests/cli_tests.py::CLITests::test_build_config_file mkdocs/tests/cli_tests.py::CLITests::test_build_defaults mkdocs/tests/cli_tests.py::CLITests::test_build_dirty mkdocs/tests/cli_tests.py::CLITests::test_build_quiet mkdocs/tests/cli_tests.py::CLITests::test_build_site_dir mkdocs/tests/cli_tests.py::CLITests::test_build_strict mkdocs/tests/cli_tests.py::CLITests::test_build_theme mkdocs/tests/cli_tests.py::CLITests::test_build_theme_dir mkdocs/tests/cli_tests.py::CLITests::test_build_verbose mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_clean mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_config_file mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_defaults mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_dirty mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_force mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_message mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_remote_branch mkdocs/tests/cli_tests.py::CLITests::test_gh_deploy_remote_name mkdocs/tests/cli_tests.py::CLITests::test_new mkdocs/tests/cli_tests.py::CLITests::test_serve_config_file mkdocs/tests/cli_tests.py::CLITests::test_serve_default mkdocs/tests/cli_tests.py::CLITests::test_serve_dev_addr mkdocs/tests/cli_tests.py::CLITests::test_serve_dirtyreload mkdocs/tests/cli_tests.py::CLITests::test_serve_livereload mkdocs/tests/cli_tests.py::CLITests::test_serve_no_livereload mkdocs/tests/cli_tests.py::CLITests::test_serve_strict mkdocs/tests/cli_tests.py::CLITests::test_serve_theme mkdocs/tests/cli_tests.py::CLITests::test_serve_theme_dir mkdocs/tests/config/config_options_tests.py::OptionallyRequiredTest::test_default mkdocs/tests/config/config_options_tests.py::OptionallyRequiredTest::test_empty mkdocs/tests/config/config_options_tests.py::OptionallyRequiredTest::test_replace_default mkdocs/tests/config/config_options_tests.py::OptionallyRequiredTest::test_required mkdocs/tests/config/config_options_tests.py::OptionallyRequiredTest::test_required_no_default mkdocs/tests/config/config_options_tests.py::TypeTest::test_length mkdocs/tests/config/config_options_tests.py::TypeTest::test_multiple_types mkdocs/tests/config/config_options_tests.py::TypeTest::test_single_type mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_default_address mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_invalid_address_format mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_invalid_address_missing_port mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_invalid_address_port mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_invalid_address_type mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_named_address mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_valid_IPv6_address mkdocs/tests/config/config_options_tests.py::IpAddressTest::test_valid_address mkdocs/tests/config/config_options_tests.py::URLTest::test_invalid mkdocs/tests/config/config_options_tests.py::URLTest::test_invalid_url mkdocs/tests/config/config_options_tests.py::URLTest::test_valid_url mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_edit_uri_bitbucket mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_edit_uri_custom mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_edit_uri_github mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_edit_uri_gitlab mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_repo_name_bitbucket mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_repo_name_custom mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_repo_name_custom_and_empty_edit_uri mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_repo_name_github mkdocs/tests/config/config_options_tests.py::RepoURLTest::test_repo_name_gitlab mkdocs/tests/config/config_options_tests.py::DirTest::test_doc_dir_is_config_dir mkdocs/tests/config/config_options_tests.py::DirTest::test_file mkdocs/tests/config/config_options_tests.py::DirTest::test_incorrect_type_attribute_error mkdocs/tests/config/config_options_tests.py::DirTest::test_incorrect_type_type_error mkdocs/tests/config/config_options_tests.py::DirTest::test_missing_dir mkdocs/tests/config/config_options_tests.py::DirTest::test_missing_dir_but_required mkdocs/tests/config/config_options_tests.py::DirTest::test_valid_dir mkdocs/tests/config/config_options_tests.py::SiteDirTest::test_common_prefix mkdocs/tests/config/config_options_tests.py::SiteDirTest::test_doc_dir_in_site_dir mkdocs/tests/config/config_options_tests.py::SiteDirTest::test_site_dir_in_docs_dir mkdocs/tests/config/config_options_tests.py::ThemeTest::test_theme_as_complex_config mkdocs/tests/config/config_options_tests.py::ThemeTest::test_theme_as_simple_config mkdocs/tests/config/config_options_tests.py::ThemeTest::test_theme_as_string mkdocs/tests/config/config_options_tests.py::ThemeTest::test_theme_config_missing_name mkdocs/tests/config/config_options_tests.py::ThemeTest::test_theme_default mkdocs/tests/config/config_options_tests.py::ThemeTest::test_theme_invalid_type mkdocs/tests/config/config_options_tests.py::ThemeTest::test_theme_name_is_none mkdocs/tests/config/config_options_tests.py::ThemeTest::test_uninstalled_theme_as_config mkdocs/tests/config/config_options_tests.py::ThemeTest::test_uninstalled_theme_as_string mkdocs/tests/config/config_options_tests.py::PagesTest::test_invalid_config mkdocs/tests/config/config_options_tests.py::PagesTest::test_invalid_type mkdocs/tests/config/config_options_tests.py::PagesTest::test_old_format mkdocs/tests/config/config_options_tests.py::PagesTest::test_provided_dict mkdocs/tests/config/config_options_tests.py::PagesTest::test_provided_empty mkdocs/tests/config/config_options_tests.py::PrivateTest::test_defined mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_builtins mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_builtins_config mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_configkey mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_duplicates mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_invalid_config_item mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_invalid_config_option mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_invalid_dict_item mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_list_dicts mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_mixed_list mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_none mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_not_list mkdocs/tests/config/config_options_tests.py::MarkdownExtensionsTest::test_simple_list mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_deploy mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_deploy_error mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_deploy_hostname mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_deploy_no_cname mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_get_current_sha mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_get_remote_url_enterprise mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_get_remote_url_http mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_get_remote_url_ssh mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_is_cwd_git_repo mkdocs/tests/gh_deploy_tests.py::TestGitHubDeploy::test_is_cwd_not_git_repo
docs/about/release-notes.md mkdocs/config/config_options.py requirements/project-min.txt
docs/about/release-notes.md mkdocs/config/config_options.py requirements/project-min.txt