diff --git a/core/modules/media/src/Form/MediaSettingsForm.php b/core/modules/media/src/Form/MediaSettingsForm.php
index 1d561de28a..94c1a75e7d 100644
--- a/core/modules/media/src/Form/MediaSettingsForm.php
+++ b/core/modules/media/src/Form/MediaSettingsForm.php
@@ -7,6 +7,8 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Drupal\media\IFrameUrlHelper;
+use Drupal\media\OEmbed\ProviderException;
+use Drupal\media\OEmbed\ProviderRepositoryInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -30,6 +32,13 @@ class MediaSettingsForm extends ConfigFormBase {
    */
   protected $entityTypeManager;
 
+  /**
+   * The oEmbed provider repository.
+   *
+   * @var \Drupal\media\OEmbed\ProviderRepositoryInterface
+   */
+  protected $providerRepository;
+
   /**
    * MediaSettingsForm constructor.
    *
@@ -39,11 +48,14 @@ class MediaSettingsForm extends ConfigFormBase {
    *   The iFrame URL helper service.
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    *   The entity type manager.
+   * @param \Drupal\media\OEmbed\ProviderRepositoryInterface $provider_repository
+   *   The oEmbed provider repository.
    */
-  public function __construct(ConfigFactoryInterface $config_factory, IFrameUrlHelper $iframe_url_helper, EntityTypeManagerInterface $entity_type_manager) {
+  public function __construct(ConfigFactoryInterface $config_factory, IFrameUrlHelper $iframe_url_helper, EntityTypeManagerInterface $entity_type_manager, ProviderRepositoryInterface $provider_repository) {
     parent::__construct($config_factory);
     $this->iFrameUrlHelper = $iframe_url_helper;
     $this->entityTypeManager = $entity_type_manager;
+    $this->providerRepository = $provider_repository;
   }
 
   /**
@@ -53,7 +65,8 @@ public static function create(ContainerInterface $container) {
     return new static(
       $container->get('config.factory'),
       $container->get('media.oembed.iframe_url_helper'),
-      $container->get('entity_type.manager')
+      $container->get('entity_type.manager'),
+      $container->get('media.oembed.provider_repository')
     );
   }
 
@@ -75,8 +88,9 @@ protected function getEditableConfigNames() {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    $domain = $this->config('media.settings')->get('iframe_domain');
+    $config = $this->config('media.settings');
 
+    $domain = $config->get('iframe_domain');
     if (!$this->iFrameUrlHelper->isSecure($domain)) {
       $message = $this->t('It is potentially insecure to display oEmbed content in a frame that is served from the same domain as your main Drupal site, as this may allow execution of third-party code. <a href="https://oembed.com/#section3" target="_blank">Take a look here for more information</a>.');
       $this->messenger()->addWarning($message);
@@ -107,12 +121,43 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#prefix' => '<hr>',
       '#type' => 'checkbox',
       '#title' => $this->t('Standalone media URL'),
-      '#default_value' => $this->config('media.settings')->get('standalone_url'),
+      '#default_value' => $config->get('standalone_url'),
       '#description' => $this->t("Allow users to access @media-entities at /media/{id}.", ['@media-entities' => $this->entityTypeManager->getDefinition('media')->getPluralLabel()]),
     ];
+
+    $form['oembed_providers_url'] = [
+      '#type' => 'url',
+      '#title' => $this->t('oEmbed providers URL'),
+      '#size' => 40,
+      '#maxlength' => 255,
+      '#required' => TRUE,
+      '#default_value' => $config->get('oembed_providers_url'),
+      '#description' => $this->t('Enter the URL from which to fetch information about all available oEmbed providers, including the http:// or https:// prefix. Generally, this should only be changed if the default URL is blocked or otherwise inaccessible.'),
+    ];
+
     return parent::buildForm($form, $form_state);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    $config = $this->config('media.settings');
+    $original_url = $config->get('oembed_providers_url');
+    $config->set('oembed_providers_url', $form_state->getValue('oembed_providers_url'))
+      ->save();
+
+    try {
+      $this->providerRepository->getAll();
+    }
+    catch (ProviderException $e) {
+      $form_state->setError($form['oembed_providers_url'], $e->getMessage());
+    }
+    finally {
+      $config->set('oembed_providers_url', $original_url)->save();
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -120,6 +165,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('media.settings')
       ->set('iframe_domain', $form_state->getValue('iframe_domain'))
       ->set('standalone_url', $form_state->getValue('standalone_url'))
+      ->set('oembed_providers_url', $form_state->getValue('oembed_providers_url'))
       ->save();
 
     parent::submitForm($form, $form_state);
diff --git a/core/modules/media/src/OEmbed/ProviderRepository.php b/core/modules/media/src/OEmbed/ProviderRepository.php
index dada7fb255..7967495c27 100644
--- a/core/modules/media/src/OEmbed/ProviderRepository.php
+++ b/core/modules/media/src/OEmbed/ProviderRepository.php
@@ -32,18 +32,18 @@ class ProviderRepository implements ProviderRepositoryInterface {
   protected $httpClient;
 
   /**
-   * URL of a JSON document which contains a database of oEmbed providers.
+   * The time service.
    *
-   * @var string
+   * @var \Drupal\Component\Datetime\TimeInterface
    */
-  protected $providersUrl;
+  protected $time;
 
   /**
-   * The time service.
+   * The config factory.
    *
-   * @var \Drupal\Component\Datetime\TimeInterface
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
    */
-  protected $time;
+  protected $configFactory;
 
   /**
    * Constructs a ProviderRepository instance.
@@ -61,7 +61,7 @@ class ProviderRepository implements ProviderRepositoryInterface {
    */
   public function __construct(ClientInterface $http_client, ConfigFactoryInterface $config_factory, TimeInterface $time, CacheBackendInterface $cache_backend = NULL, $max_age = 604800) {
     $this->httpClient = $http_client;
-    $this->providersUrl = $config_factory->get('media.settings')->get('oembed_providers_url');
+    $this->configFactory = $config_factory;
     $this->time = $time;
     $this->cacheBackend = $cache_backend;
     $this->maxAge = (int) $max_age;
@@ -78,11 +78,12 @@ public function getAll() {
       return $cached->data;
     }
 
+    $url = $this->configFactory->get('media.settings')->get('oembed_providers_url');
     try {
-      $response = $this->httpClient->request('GET', $this->providersUrl);
+      $response = $this->httpClient->request('GET', $url);
     }
     catch (RequestException $e) {
-      throw new ProviderException("Could not retrieve the oEmbed provider database from $this->providersUrl", NULL, $e);
+      throw new ProviderException("Could not retrieve the oEmbed provider database from $url", NULL, $e);
     }
 
     $providers = Json::decode((string) $response->getBody());
diff --git a/core/modules/media/tests/src/Functional/MediaSettingsTest.php b/core/modules/media/tests/src/Functional/MediaSettingsTest.php
index ba25392f5c..4293702fbb 100644
--- a/core/modules/media/tests/src/Functional/MediaSettingsTest.php
+++ b/core/modules/media/tests/src/Functional/MediaSettingsTest.php
@@ -14,7 +14,11 @@ class MediaSettingsTest extends MediaFunctionalTestBase {
    */
   protected function setUp() {
     parent::setUp();
-    $this->drupalLogin($this->createUser(['administer site configuration']));
+    $account = $this->createUser([
+      'administer site configuration',
+      'administer media',
+    ]);
+    $this->drupalLogin($account);
   }
 
   /**
@@ -22,6 +26,7 @@ protected function setUp() {
    */
   public function testStatusPage() {
     $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
 
     $this->drupalGet('admin/reports/status');
     $assert_session->pageTextNotContains('It is potentially insecure to display oEmbed content in a frame');
@@ -30,6 +35,42 @@ public function testStatusPage() {
 
     $this->drupalGet('admin/reports/status');
     $assert_session->pageTextContains('It is potentially insecure to display oEmbed content in a frame');
+
+    $default_providers_url = $this->config('media.settings')->get('oembed_providers_url');
+    $providers_uri = 'public://providers.json';
+    $providers_url = file_create_url($providers_uri);
+    $this->assertNotEmpty($providers_url);
+
+    $this->drupalGet('/admin/config/media/media-settings');
+    $assert_session->fieldValueEquals('oEmbed providers URL', $default_providers_url);
+
+    // Ensure that a bogus oEmbed providers URL is rejected.
+    $page->fillField('oEmbed providers URL', 'https://foo.baz');
+    $page->pressButton('Save configuration');
+    $assert_session->pageTextContains('Could not retrieve the oEmbed provider database from https://foo.baz');
+    $this->assertSame($default_providers_url, $this->config('media.settings')->get('oembed_providers_url'));
+
+    // Try to set the oEmbed providers URL to a valid URL that doesn't actually
+    // exist, and ensure that it is rejected.
+    $page->fillField('oEmbed providers URL', $providers_url);
+    $page->pressButton('Save configuration');
+    $assert_session->pageTextContains("Could not retrieve the oEmbed provider database from $providers_url");
+    $this->assertSame($default_providers_url, $this->config('media.settings')->get('oembed_providers_url'));
+
+    // Create a providers.json with random detritus in it and ensure that it
+    // is rejected.
+    file_put_contents($providers_uri, $this->getRandomGenerator()->paragraphs());
+    $page->fillField('oEmbed providers URL', $providers_url);
+    $page->pressButton('Save configuration');
+    $assert_session->pageTextContains('Remote oEmbed providers database returned invalid or empty list.');
+    $this->assertSame($default_providers_url, $this->config('media.settings')->get('oembed_providers_url'));
+
+    // Create a providers.json with a valid, but empty, array in it and ensure
+    // that it is rejected.
+    file_put_contents($providers_uri, '[]');
+    $page->pressButton('Save configuration');
+    $assert_session->pageTextContains('Remote oEmbed providers database returned invalid or empty list.');
+    $this->assertSame($default_providers_url, $this->config('media.settings')->get('oembed_providers_url'));
   }
 
 }
diff --git a/core/modules/media/tests/src/Kernel/ProviderRepositoryTest.php b/core/modules/media/tests/src/Kernel/ProviderRepositoryTest.php
new file mode 100644
index 0000000000..5f64191848
--- /dev/null
+++ b/core/modules/media/tests/src/Kernel/ProviderRepositoryTest.php
@@ -0,0 +1,136 @@
+<?php
+
+namespace Drupal\Tests\media\Kernel;
+
+use Drupal\media\OEmbed\ProviderException;
+use Drupal\media\OEmbed\ProviderRepository;
+use GuzzleHttp\Exception\RequestException;
+use Drupal\Component\Datetime\TimeInterface;
+use GuzzleHttp\Client;
+use GuzzleHttp\Psr7\Response;
+
+/**
+ * Tests the oEmbed provider repository.
+ *
+ * @coversDefaultClass \Drupal\media\OEmbed\ProviderRepository
+ *
+ * @group media
+ */
+class ProviderRepositoryTest extends MediaKernelTestBase {
+
+  /**
+   * The HTTP client to fetch the feed data with.
+   *
+   * @var \GuzzleHttp\ClientInterface
+   */
+  protected $httpClient;
+
+  /**
+   * The configuration factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The time service.
+   *
+   * @var \Drupal\Component\Datetime\TimeInterface
+   */
+  protected $time;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->httpClient = $this->createMock(Client::class);
+    $this->configFactory = $this->container->get('config.factory');
+    $this->time = $this->prophesize(TimeInterface::class);
+  }
+
+  /**
+   * Tests that provider discovery fails with a non-existent provider database.
+   *
+   * @param string $providers_url
+   *   The URL of the provider database.
+   * @param string $exception_message
+   *   The expected exception message.
+   *
+   * @covers ::getAll
+   * @dataProvider providerNonExistingProviderDatabase
+   */
+  public function testNonExistingProviderDatabase($providers_url, $exception_message) {
+    $this->configFactory->getEditable('media.settings')
+      ->set('oembed_providers_url', $providers_url)
+      ->save();
+
+    $exception = new RequestException('Some sort of error occurred!', $this->prophesize('\Psr\Http\Message\RequestInterface')->reveal());
+
+    $this->httpClient->method('request')
+      ->with('GET', $providers_url)
+      ->willThrowException($exception);
+
+    $repository = new ProviderRepository($this->httpClient, $this->configFactory, $this->time->reveal());
+
+    $this->expectException(ProviderException::class);
+    $this->expectExceptionMessage($exception_message);
+    $repository->get('media.oembed.provider_repository')->getAll();
+  }
+
+  /**
+   * Data provider for testEmptyProviderList().
+   *
+   * @see ::testEmptyProviderList()
+   *
+   * @return array
+   */
+  public function providerNonExistingProviderDatabase() {
+    return [
+      [
+        'http://oembed1.com/providers.json',
+        'Could not retrieve the oEmbed provider database from http://oembed1.com/providers.json',
+      ],
+      [
+        'http://oembed.com/providers1.json',
+        'Could not retrieve the oEmbed provider database from http://oembed.com/providers1.json',
+      ],
+    ];
+  }
+
+  /**
+   * Tests that provider discovery fails if the provider database is empty.
+   *
+   * @param string $content
+   *   The expected JSON content of the provider database.
+   *
+   * @covers ::getAll
+   * @dataProvider providerEmptyProviderList
+   */
+  public function testEmptyProviderList($content) {
+    $this->httpClient->method('request')
+      ->withAnyParameters()
+      ->willReturn(new Response(200, [], $content));
+
+    $repository = new ProviderRepository($this->httpClient, $this->configFactory, $this->time->reveal());
+
+    $this->expectException(ProviderException::class);
+    $this->expectExceptionMessage('Remote oEmbed providers database returned invalid or empty list.');
+    $repository->getAll();
+  }
+
+  /**
+   * Data provider for testEmptyProviderList().
+   *
+   * @see ::testEmptyProviderList()
+   *
+   * @return array
+   */
+  public function providerEmptyProviderList() {
+    return [
+      'empty array' => ['[]'],
+      'empty string' => [''],
+    ];
+  }
+
+}
