diff --git a/core/core.services.yml b/core/core.services.yml
index 737009b..5c45190 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -354,6 +354,9 @@ services:
     class: Drupal\Core\Database\Connection
     factory: Drupal\Core\Database\Database::getConnection
     arguments: [default]
+  database.driver.discovery:
+    class: Drupal\Core\Database\DatabaseDriverDiscovery
+    arguments: ['@app.root']
   datetime.time:
     class: Drupal\Component\Datetime\Time
     arguments: ['@request_stack']
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index a869d90..d7d561c 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -327,8 +327,9 @@ function install_begin_request($class_loader, &$install_state) {
     date_default_timezone_set('Australia/Sydney');
   }
 
+  $app_root = dirname(dirname(__DIR__));
   $site_path = DrupalKernel::findSitePath($request, FALSE);
-  Settings::initialize(dirname(dirname(__DIR__)), $site_path, $class_loader);
+  Settings::initialize($app_root, $site_path, $class_loader);
 
   // Ensure that procedural dependencies are loaded as early as possible,
   // since the error/exception handlers depend on them.
@@ -358,6 +359,11 @@ function install_begin_request($class_loader, &$install_state) {
     ->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
     ->addArgument(new Reference('language.default'));
 
+  // Register the database driver discovery service.
+  $container
+    ->register('database.driver.discovery', 'Drupal\Core\Database\DatabaseDriverDiscovery')
+    ->addArgument($app_root);
+
   // Register the stream wrapper manager.
   $container
     ->register('stream_wrapper_manager', 'Drupal\Core\StreamWrapper\StreamWrapperManager')
@@ -1150,14 +1156,14 @@ function install_database_errors($database, $settings_file) {
   $errors = [];
 
   // Check database type.
-  $database_types = drupal_get_database_types();
+  $installable_drivers = \Drupal::service('database.driver.discovery')->getInstallableDriversInstallers();
   $driver = $database['driver'];
-  if (!isset($database_types[$driver])) {
+  if (!isset($installable_drivers[$driver])) {
     $errors['driver'] = t("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", ['%settings_file' => $settings_file, '@drupal' => drupal_install_profile_distribution_name(), '%driver' => $driver]);
   }
   else {
     // Run driver specific validation
-    $errors += $database_types[$driver]->validateDatabaseSettings($database);
+    $errors += $installable_drivers[$driver]->validateDatabaseSettings($database);
     if (!empty($errors)) {
       // No point to try further.
       return $errors;
@@ -1166,7 +1172,7 @@ function install_database_errors($database, $settings_file) {
     // calling function.
     Database::addConnectionInfo('default', 'default', $database);
 
-    $errors = db_installer_object($driver)->runTasks();
+    $errors = $installable_drivers[$driver]->runTasks();
   }
   return $errors;
 }
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 3529d51..165eaa5 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -141,15 +141,16 @@ function drupal_install_profile_distribution_version() {
  *
  * @return
  *   An array of database types compiled into PHP.
+ *
+ * @deprecated in Drupal 8.5.0, will be removed before Drupal 9.0.0. Use
+ *   \Drupal::service('database.driver.discovery')->getInstallableDriversInstallerNames
+ *   instead.
+ *
+ * @see https://www.drupal.org/node/2896416
  */
 function drupal_detect_database_types() {
-  $databases = drupal_get_database_types();
-
-  foreach ($databases as $driver => $installer) {
-    $databases[$driver] = $installer->name();
-  }
-
-  return $databases;
+  @trigger_error('drupal_detect_database_types() is deprecated in Drupal 8.5.0, will be removed before Drupal 9.0.0. Use \Drupal::service(\'database.driver.discovery\')->getInstallableDriversInstallerNames instead. See https://www.drupal.org/node/2896416.', E_USER_DEPRECATED);
+  return \Drupal::service('database.driver.discovery')->getInstallableDriversInstallerNames();
 }
 
 /**
@@ -157,37 +158,16 @@ function drupal_detect_database_types() {
  *
  * @return \Drupal\Core\Database\Install\Tasks[]
  *   An array of available database driver installer objects.
+ *
+ * @deprecated in Drupal 8.5.0, will be removed before Drupal 9.0.0. Use
+ *   \Drupal::service('database.driver.discovery')->getInstallableDriversInstallers
+ *   instead.
+ *
+ * @see https://www.drupal.org/node/2896416
  */
 function drupal_get_database_types() {
-  $databases = [];
-  $drivers = [];
-
-  // The internal database driver name is any valid PHP identifier.
-  $mask = '/^' . DRUPAL_PHP_FUNCTION_PATTERN . '$/';
-  $files = file_scan_directory(DRUPAL_ROOT . '/core/lib/Drupal/Core/Database/Driver', $mask, ['recurse' => FALSE]);
-  if (is_dir(DRUPAL_ROOT . '/drivers/lib/Drupal/Driver/Database')) {
-    $files += file_scan_directory(DRUPAL_ROOT . '/drivers/lib/Drupal/Driver/Database/', $mask, ['recurse' => FALSE]);
-  }
-  foreach ($files as $file) {
-    if (file_exists($file->uri . '/Install/Tasks.php')) {
-      $drivers[$file->filename] = $file->uri;
-    }
-  }
-  foreach ($drivers as $driver => $file) {
-    $installer = db_installer_object($driver);
-    if ($installer->installable()) {
-      $databases[$driver] = $installer;
-    }
-  }
-
-  // Usability: unconditionally put the MySQL driver on top.
-  if (isset($databases['mysql'])) {
-    $mysql_database = $databases['mysql'];
-    unset($databases['mysql']);
-    $databases = ['mysql' => $mysql_database] + $databases;
-  }
-
-  return $databases;
+  @trigger_error('drupal_get_database_types() is deprecated in Drupal 8.5.0, will be removed before Drupal 9.0.0. Use \Drupal::service(\'database.driver.discovery\')->getInstallableDriversInstaller instead. See https://www.drupal.org/node/2896416.', E_USER_DEPRECATED);
+  return \Drupal::service('database.driver.discovery')->getInstallableDriversInstallers();
 }
 
 /**
@@ -1107,16 +1087,13 @@ function install_profile_info($profile, $langcode = 'en') {
  *
  * @return \Drupal\Core\Database\Install\Tasks
  *   A class defining the requirements and tasks for installing the database.
+ *
+ * @deprecated in Drupal 8.5.0, will be removed before Drupal 9.0.0. Use
+ *   \Drupal::service('database.driver.discovery')->getInstaller instead.
+ *
+ * @see https://www.drupal.org/node/2896416
  */
 function db_installer_object($driver) {
-  // We cannot use Database::getConnection->getDriverClass() here, because
-  // the connection object is not yet functional.
-  $task_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Install\\Tasks";
-  if (class_exists($task_class)) {
-    return new $task_class();
-  }
-  else {
-    $task_class = "Drupal\\Driver\\Database\\{$driver}\\Install\\Tasks";
-    return new $task_class();
-  }
+  @trigger_error('db_installer_object() is deprecated in Drupal 8.5.0, will be removed before Drupal 9.0.0. Use \Drupal::service(\'database.driver.discovery\')->getInstaller instead. See https://www.drupal.org/node/2896416.', E_USER_DEPRECATED);
+  return \Drupal::service('database.driver.discovery')->getInstaller($driver);
 }
diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php
index 100ef68..262cf3b 100644
--- a/core/lib/Drupal/Core/Database/Connection.php
+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Core\Database;
 
+use Psr\Http\Message\UriInterface;
+
 /**
  * Base Database API class.
  *
@@ -1472,4 +1474,69 @@ public function __sleep() {
     throw new \LogicException('The database connection is not serializable. This probably means you are serializing an object that has an indirect reference to the database connection. Adjust your code so that is not necessary. Alternatively, look at DependencySerializationTrait as a temporary solution.');
   }
 
+  /**
+   * A helper function to convert a URI into connection options.
+   *
+   * @internal
+   *   This method should not be called. Use
+   *   \Drupal\Core\Database\Database::convertDbUrlToConnectionInfo() instead.
+   *
+   * @param \Psr\Http\Message\UriInterface $uri
+   *   The URI to be converted to a connection array.
+   * @param string $root
+   *   The root directory of the Drupal installation. Some database drivers,
+   *   like for example SQLite, need this information.
+   * @param array $connection_options
+   *   The connection options.
+   *
+   * @return array
+   *   The connection options.
+   *
+   * @see \Drupal\Core\Database\Database::convertDbUrlToConnectionInfo()
+   */
+  public static function convertDbUrlToConnectionInfoHelper(UriInterface $uri, $root, array $connection_options) {
+    $port = $uri->getPort();
+    if (!empty($port)) {
+      $connection_options['port'] = $port;
+    }
+
+    $user_info = $uri->getUserInfo();
+    if (!empty($user_info)) {
+      $user_info_elements = explode(':', $user_info, 2);
+      $connection_options['username'] = $user_info_elements[0];
+      $connection_options['password'] = isset($user_info_elements[1]) ? $user_info_elements[1] : '';
+    }
+
+    return $connection_options;
+  }
+
+  /**
+   * A helper function to convert connection options into a URI.
+   *
+   * @internal
+   *   This method should not be called. Use
+   *   \Drupal\Core\Database\Database::getConnectionInfoAsUrl() instead.
+   *
+   * @param array $connection_options
+   *   The array of connection options for a database connection.
+   * @param \Psr\Http\Message\UriInterface $uri
+   *   The URI to connect to the database.
+   *
+   * @return \Psr\Http\Message\UriInterface
+   *   The URI to connect to the database.
+   *
+   * @see \Drupal\Core\Database\Database::getConnectionInfoAsUrl()
+   */
+  public static function getConnectionInfoAsUrlHelper(array $connection_options, UriInterface $uri) {
+    $username = isset($connection_options['username']) ? $connection_options['username'] : NULL;
+    $password = isset($connection_options['password']) ? $connection_options['password'] : NULL;
+    if ($username) {
+      $uri = $uri->withUserInfo($username, $password);
+    }
+    if (!empty($connection_options['port'])) {
+      $uri = $uri->withPort($connection_options['port']);
+    }
+    return $uri;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Database/Database.php b/core/lib/Drupal/Core/Database/Database.php
index dd19018..8ce683a 100644
--- a/core/lib/Drupal/Core/Database/Database.php
+++ b/core/lib/Drupal/Core/Database/Database.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Core\Database;
 
+use GuzzleHttp\Psr7\Uri;
+
 /**
  * Primary front-controller for the database system.
  *
@@ -365,16 +367,11 @@
       throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
     }
 
-    if (!empty(self::$databaseInfo[$key][$target]['namespace'])) {
-      $driver_class = self::$databaseInfo[$key][$target]['namespace'] . '\\Connection';
-    }
-    else {
-      // Fallback for Drupal 7 settings.php.
-      $driver_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Connection";
-    }
+    $namespace = static::getDatabaseDriverNamespace(self::$databaseInfo[$key][$target]);
+    $connection_class = $namespace . '\\Connection';
 
-    $pdo_connection = $driver_class::open(self::$databaseInfo[$key][$target]);
-    $new_connection = new $driver_class($pdo_connection, self::$databaseInfo[$key][$target]);
+    $pdo_connection = $connection_class::open(self::$databaseInfo[$key][$target]);
+    $new_connection = new $connection_class($pdo_connection, self::$databaseInfo[$key][$target]);
     $new_connection->setTarget($target);
     $new_connection->setKey($key);
 
@@ -453,38 +450,44 @@ public static function ignoreTarget($key, $target) {
    * @throws \InvalidArgumentException
    *   Exception thrown when the provided URL does not meet the minimum
    *   requirements.
+   * @throws \RuntimeException
+   *   When the database driver is not available, or the URL can not be
+   *   converted to a database connection array.
    */
   public static function convertDbUrlToConnectionInfo($url, $root) {
-    $info = parse_url($url);
-    if (!isset($info['scheme'], $info['host'], $info['path'])) {
+    $uri = new Uri($url);
+    if (empty($uri->getHost()) || empty($uri->getScheme()) || empty($uri->getPath())) {
       throw new \InvalidArgumentException('Minimum requirement: driver://host/database');
     }
-    $info += [
-      'user' => '',
-      'pass' => '',
-      'fragment' => '',
-    ];
 
-    // A SQLite database path with two leading slashes indicates a system path.
-    // Otherwise the path is relative to the Drupal root.
-    if ($info['path'][0] === '/') {
-      $info['path'] = substr($info['path'], 1);
+    // Discover if the URL has a driver namespace.
+    $scheme = $uri->getScheme();
+    $drivers = \Drupal::service('database.driver.discovery')->discoverDatabaseDrivers();
+    if (!isset($drivers[$scheme])) {
+      throw new \RuntimeException("Drupal database driver not available: '" . $uri->getScheme() . "'");
     }
-    if ($info['scheme'] === 'sqlite' && $info['path'][0] !== '/') {
-      $info['path'] = $root . '/' . $info['path'];
-    }
-
-    $database = [
-      'driver' => $info['scheme'],
-      'username' => $info['user'],
-      'password' => $info['pass'],
-      'host' => $info['host'],
-      'database' => $info['path'],
+    $namespace = $drivers[$scheme]['namespace'];
+
+    // Build the connection information array.
+    $connection_options = [
+      'driver' => $uri->getScheme(),
+      'host' => $uri->getHost(),
+      // Strip the first leading slash of the path to get the database name.
+      // Note that additional leading slashes have meaning for some database
+      // drivers.
+      'database' => substr($uri->getPath(), 1),
+      'prefix' => $uri->getFragment() ?: NULL,
+      'namespace' => $namespace,
     ];
-    if (isset($info['port'])) {
-      $database['port'] = $info['port'];
+
+    // Ensure the Connection class exists.
+    $namespace = static::getDatabaseDriverNamespace($connection_options);
+    $connection_class = $namespace . '\\Connection';
+    if (!class_exists($connection_class)) {
+      throw new \RuntimeException("Can not convert $url to a database connection, class $connection_class does not exist");
     }
-    return $database;
+
+    return $connection_class::convertDbUrlToConnectionInfoHelper($uri, $root, $connection_options);
   }
 
   /**
@@ -495,32 +498,68 @@ public static function convertDbUrlToConnectionInfo($url, $root) {
    *
    * @return string
    *   The connection info as a URL.
+   *
+   * @throws \RuntimeException
+   *   When the database connection is not defined.
    */
   public static function getConnectionInfoAsUrl($key = 'default') {
     $db_info = static::getConnectionInfo($key);
-    if ($db_info['default']['driver'] == 'sqlite') {
-      $db_url = 'sqlite://localhost/' . $db_info['default']['database'];
+    if (empty($db_info)) {
+      throw new \RuntimeException("Database connection $key not defined");
     }
-    else {
-      $user = '';
-      if ($db_info['default']['username']) {
-        $user = $db_info['default']['username'];
-        if ($db_info['default']['password']) {
-          $user .= ':' . $db_info['default']['password'];
-        }
-        $user .= '@';
-      }
+    return static::convertConnectionInfoToUrl($db_info);
+  }
 
-      $db_url = $db_info['default']['driver'] . '://' . $user . $db_info['default']['host'];
-      if (isset($db_info['default']['port'])) {
-        $db_url .= ':' . $db_info['default']['port'];
-      }
-      $db_url .= '/' . $db_info['default']['database'];
+  /**
+   * Convert a database connection info array to a URL.
+   *
+   * @param array $db_info
+   *   The database connection info.
+   *
+   * @return string
+   *   The connection info as a URL.
+   */
+  public static function convertConnectionInfoToUrl($db_info) {
+
+    $namespace = static::getDatabaseDriverNamespace($db_info['default']);
+    $connection_class = $namespace . '\\Connection';
+
+    // Some database driver do not need a host setting to work but in order to
+    // be converted into a URL they do.
+    $host = isset($db_info['default']['host']) ? $db_info['default']['host'] : 'localhost';
+
+    // Create a URI with the minimum requirement of driver://host/database.
+    $uri = new Uri();
+    $uri = $uri->withScheme($db_info['default']['driver'])
+      ->withHost($host)
+      ->withPath('/' . $db_info['default']['database']);
+
+    if (!empty($db_info['default']['prefix']['default'])) {
+      $uri = $uri->withFragment($db_info['default']['prefix']['default']);
     }
-    if ($db_info['default']['prefix']['default']) {
-      $db_url .= '#' . $db_info['default']['prefix']['default'];
+
+    $uri = $connection_class::getConnectionInfoAsUrlHelper($db_info['default'], $uri);
+    return (string) $uri;
+  }
+
+  /**
+   * Gets the PHP namespace of a database driver.
+   *
+   * @param array $connection_info
+   *   The database connection information, as defined in settings.php. The
+   *   structure of this array depends on the database driver it is connecting
+   *   to.
+   *
+   * @return string
+   *   The PHP namespace of the driver's database.
+   */
+  public static function getDatabaseDriverNamespace(array $connection_info) {
+    if (isset($connection_info['namespace']) && $connection_info['namespace'] !== NULL) {
+      return $connection_info['namespace'];
     }
-    return $db_url;
+
+    // Fallback for Drupal 7 settings.php.
+    return 'Drupal\\Core\\Database\\Driver\\' . $connection_info['driver'];
   }
 
 }
diff --git a/core/lib/Drupal/Core/Database/DatabaseDriverDiscovery.php b/core/lib/Drupal/Core/Database/DatabaseDriverDiscovery.php
new file mode 100644
index 0000000..1d40d6a
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/DatabaseDriverDiscovery.php
@@ -0,0 +1,159 @@
+<?php
+
+namespace Drupal\Core\Database;
+
+/**
+ * Performs database driver discovery.
+ */
+class DatabaseDriverDiscovery {
+
+  /**
+   * The app root.
+   *
+   * @var string
+   */
+  protected $appRoot;
+
+  /**
+   * Constructs a DatabaseDriverDiscovery object.
+   *
+   * @param string $app_root
+   *   The app root.
+   */
+  public function __construct($app_root) {
+    $this->appRoot = $app_root;
+  }
+
+  /**
+   * Returns locations of directories for database drivers discovery.
+   *
+   * See composer.json for discoverable namespaces.
+   *
+   * @return array
+   *   An associative array with key the possible drivers namespaces, and value
+   *   the directory where the database driver code should be located.
+   */
+  protected function getDiscoveryLocations() {
+    return [
+      'Drupal\\Core\\Database\\Driver' => __DIR__ . '/Driver',
+      'Drupal\\Driver\\Database' => $this->appRoot . '/drivers/lib/Drupal/Driver/Database',
+    ];
+  }
+
+  /**
+   * Returns the installer name of the installable database drivers.
+   *
+   * @return \Drupal\Core\StringTranslation\TranslatableMarkup[]
+   *   An associative array with key the database driver name, and value the
+   *   name of database driver as presented by the installer.
+   */
+  public function getInstallableDriversInstallerNames() {
+    $installable_drivers_installers_names = [];
+
+    foreach ($this->getInstallableDriversInstallers() as $driver_name => $installer) {
+      $installable_drivers_installers_names[$driver_name] = $installer->name();
+    }
+
+    return $installable_drivers_installers_names;
+  }
+
+  /**
+   * Returns the installer objects of the installable database drivers.
+   *
+   * @return \Drupal\Core\Database\Install\Tasks[]
+   *   An associative array with key the database driver name, and value the
+   *   installer object.
+   */
+  public function getInstallableDriversInstallers() {
+    $installable_drivers_installers = [];
+
+    foreach ($this->discoverDatabaseDrivers() as $driver_name => $info) {
+      if ($info['installable'] === TRUE) {
+        $installable_drivers_installers[$driver_name] = $info['installer'];
+      }
+    }
+
+    // Usability: unconditionally put the MySQL driver on top.
+    if (isset($installable_drivers_installers['mysql'])) {
+      $mysql_driver_installer = $installable_drivers_installers['mysql'];
+      unset($installable_drivers_installers['mysql']);
+      $installable_drivers_installers = ['mysql' => $mysql_driver_installer] + $installable_drivers_installers;
+    }
+
+    return $installable_drivers_installers;
+  }
+
+  /**
+   * Returns a database installer object.
+   *
+   * @param string $driver_name
+   *   The name of the driver.
+   *
+   * @return \Drupal\Core\Database\Install\Tasks
+   *   A class defining the requirements and tasks for installing the database.
+   */
+  public function getInstaller($driver_name) {
+    return $this->discoverDatabaseDrivers()[$driver_name]['installer'];
+  }
+
+  /**
+   * Discovers the available database drivers.
+   *
+   * @return array
+   *   An associative array with key the database driver name, and value an
+   *   associative array bearing the following keys and values:
+   *   - 'namespace' => the PHP namespace for this driver;
+   *   - 'connectionClass' => the FQCN of the Connection class for this driver;
+   *   - 'installer' => the database driver installer object;
+   *   - 'installable' => whether the database driver can be installed.
+   *
+   * @throws \RuntimeException
+   *   When there are duplicated driver names.
+   */
+  public function discoverDatabaseDrivers() {
+    // Scan the discovery locations and build an array of candidate discovered
+    // drivers.
+    $candidate_drivers = [];
+    foreach ($this->getDiscoveryLocations() as $namespace => $location) {
+      if (is_dir($location) && ($handle = @opendir($location))) {
+        // Each database driver name should correspond to a subdirectory of the
+        // location being scanned.
+        while (($driver_name = readdir($handle)) != FALSE) {
+          // Skip this file if it starts with a dot.
+          if ($driver_name[0] != '.' && is_dir($location . '/' . $driver_name)) {
+            if (isset($candidate_drivers[$driver_name])) {
+              throw new \RuntimeException("Duplicate database driver name found: " . $driver_name);
+            }
+            $candidate_drivers[$driver_name] = $namespace . '\\' . $driver_name;
+          }
+        }
+      }
+    }
+
+    // Loops through the candidates and build the array of discovered drivers.
+    // Use class_exist to check that actual classes for Connection and
+    // Install\Tasks are defined and can be loaded.
+    $discoveredDrivers = [];
+    foreach ($candidate_drivers as $driver_name => $namespace) {
+      $connection_class = $namespace . '\\Connection';
+      if (!class_exists($connection_class)) {
+        continue;
+      }
+      $discoveredDrivers[$driver_name]['namespace'] = $namespace;
+      $discoveredDrivers[$driver_name]['connectionClass'] = $connection_class;
+      $install_tasks_class = $namespace . '\\Install\\Tasks';
+      if (class_exists($install_tasks_class)) {
+        $installer = new $install_tasks_class();
+        $discoveredDrivers[$driver_name]['installer'] = $installer;
+        $discoveredDrivers[$driver_name]['installable'] = $installer->installable();
+      }
+      else {
+        $discoveredDrivers[$driver_name]['installer'] = NULL;
+        $discoveredDrivers[$driver_name]['installable'] = FALSE;
+      }
+    }
+
+    return $discoveredDrivers;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
index a7c1496..ef81c47 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Database\DatabaseNotFoundException;
 use Drupal\Core\Database\Connection as DatabaseConnection;
+use Psr\Http\Message\UriInterface;
 
 /**
  * SQLite implementation of \Drupal\Core\Database\Connection.
@@ -436,4 +437,30 @@ public function getFullQualifiedTableName($table) {
     return $prefix . $table;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function convertDbUrlToConnectionInfoHelper(UriInterface $uri, $root, array $connection_options) {
+    // A SQLite database with a leading slash indicates a system path.
+    // Otherwise the path is relative to the Drupal root.
+    if ($connection_options['database'][0] !== '/') {
+      $connection_options['database'] = $root . '/' . $connection_options['database'];
+    }
+    // The host setting is meaningless for SQLite databases.
+    unset($connection_options['host']);
+    return $connection_options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getConnectionInfoAsUrlHelper(array $connection_options, UriInterface $uri) {
+    if ($connection_options['database'][0] === '/') {
+      // If the database is an absolute path add an additional leading slash to
+      // denote this.
+      $uri = $uri->withPath('/' . $connection_options['database']);
+    }
+    return $uri;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
index 300def9..c73a84a 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
@@ -66,8 +66,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
 
     $form['#title'] = $this->t('Database configuration');
 
-    $drivers = drupal_get_database_types();
-    $drivers_keys = array_keys($drivers);
+    $installable_drivers = \Drupal::service('database.driver.discovery')->getInstallableDriversInstallers();
+    $installable_drivers_keys = array_keys($installable_drivers);
 
     // Unless there is input for this form (for a non-interactive installation,
     // input originates from the $settings array passed into install_drupal()),
@@ -98,7 +98,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     // as default value, so that its settings form is made visible via #states
     // when JavaScript is enabled (see below).
     else {
-      $default_driver = current($drivers_keys);
+      $default_driver = current($installable_drivers_keys);
       $default_options = [];
     }
 
@@ -108,12 +108,12 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#required' => TRUE,
       '#default_value' => $default_driver,
     ];
-    if (count($drivers) == 1) {
+    if (count($installable_drivers) == 1) {
       $form['driver']['#disabled'] = TRUE;
     }
 
     // Add driver specific configuration options.
-    foreach ($drivers as $key => $driver) {
+    foreach ($installable_drivers as $key => $driver) {
       $form['driver']['#options'][$key] = $driver->name();
 
       $form['settings'][$key] = $driver->getFormOptions($default_options);
@@ -152,11 +152,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   public function validateForm(array &$form, FormStateInterface $form_state) {
     $driver = $form_state->getValue('driver');
     $database = $form_state->getValue($driver);
-    $drivers = drupal_get_database_types();
-    $reflection = new \ReflectionClass($drivers[$driver]);
-    $install_namespace = $reflection->getNamespaceName();
-    // Cut the trailing \Install from namespace.
-    $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
+    $discovered_drivers = \Drupal::service('database.driver.discovery')->discoverDatabaseDrivers();
+    $database['namespace'] = $discovered_drivers[$driver]['namespace'];
     $database['driver'] = $driver;
 
     $form_state->set('database', $database);
diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index 3165815..164247b 100644
--- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -656,7 +656,7 @@ protected function prepareEnvironment() {
   /**
    * Returns all supported database driver installer objects.
    *
-   * This wraps drupal_get_database_types() for use without a current container.
+   * This swaps the original container for use without a current container.
    *
    * @return \Drupal\Core\Database\Install\Tasks[]
    *   An array of available database driver installer objects.
@@ -665,7 +665,7 @@ protected function getDatabaseTypes() {
     if ($this->originalContainer) {
       \Drupal::setContainer($this->originalContainer);
     }
-    $database_types = drupal_get_database_types();
+    $database_types = \Drupal::service('database.driver.discovery')->getInstallableDriversInstallers();
     if ($this->originalContainer) {
       \Drupal::unsetContainer();
     }
diff --git a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
index 898a8a5..7e403d9 100644
--- a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
+++ b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
@@ -69,6 +69,13 @@ class MigrateUpgradeForm extends ConfirmFormBase {
   protected $moduleHandler;
 
   /**
+   * The database discovery service.
+   *
+   * @var \Drupal\Core\Database\DatabaseDriverDiscovery
+   */
+  protected $databaseDriverDiscovery;
+
+  /**
    * Constructs the MigrateUpgradeForm.
    *
    * @param \Drupal\Core\State\StateInterface $state
@@ -83,14 +90,17 @@ class MigrateUpgradeForm extends ConfirmFormBase {
    *   The field plugin manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Drupal\Core\Database\DatabaseDriverDiscovery $database_driver_discovery
+   *   The database discovery service.
    */
-  public function __construct(StateInterface $state, DateFormatterInterface $date_formatter, RendererInterface $renderer, MigrationPluginManagerInterface $plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, ModuleHandlerInterface $module_handler) {
+  public function __construct(StateInterface $state, DateFormatterInterface $date_formatter, RendererInterface $renderer, MigrationPluginManagerInterface $plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, ModuleHandlerInterface $module_handler, DatabaseDriverDiscovery $database_driver_discovery) {
     $this->state = $state;
     $this->dateFormatter = $date_formatter;
     $this->renderer = $renderer;
     $this->pluginManager = $plugin_manager;
     $this->fieldPluginManager = $field_plugin_manager;
     $this->moduleHandler = $module_handler;
+    $this->databaseDriverDiscovery = $database_driver_discovery;
   }
 
   /**
@@ -103,7 +113,8 @@ public static function create(ContainerInterface $container) {
       $container->get('renderer'),
       $container->get('plugin.manager.migration'),
       $container->get('plugin.manager.migrate.field'),
-      $container->get('module_handler')
+      $container->get('module_handler'),
+      $container->get('database.driver.discovery')
     );
   }
 
@@ -381,21 +392,16 @@ public function buildCredentialForm(array $form, FormStateInterface $form_state)
    */
   public function validateCredentialForm(array &$form, FormStateInterface $form_state) {
 
-    // Retrieve the database driver from the form, use reflection to get the
-    // namespace, and then construct a valid database array the same as in
-    // settings.php.
+    // Retrieve the database driver from the form and construct a valid database
+    // array the same as in settings.php.
+    $discovered_drivers = \Drupal::service('database.driver.discovery')->discoverDatabaseDrivers();
     $driver = $form_state->getValue('driver');
-    $drivers = $this->getDatabaseTypes();
-    $reflection = new \ReflectionClass($drivers[$driver]);
-    $install_namespace = $reflection->getNamespaceName();
-
     $database = $form_state->getValue($driver);
-    // Cut the trailing \Install from namespace.
-    $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
+    $database['namespace'] = $discovered_drivers[$driver]['namespace'];
     $database['driver'] = $driver;
 
     // Validate the driver settings and just end here if we have any issues.
-    if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
+    if ($errors = $discovered_drivers[$driver]->validateDatabaseSettings($database)) {
       foreach ($errors as $name => $message) {
         $form_state->setErrorByName($name, $message);
       }
@@ -842,9 +848,7 @@ public function submitConfirmForm(array &$form, FormStateInterface $form_state)
    *   An array of available database driver installer objects.
    */
   protected function getDatabaseTypes() {
-    // Make sure the install API is available.
-    include_once DRUPAL_ROOT . '/core/includes/install.inc';
-    return drupal_get_database_types();
+    return $this->databaseDriverDiscovery->getInstallableDriversInstallers();
   }
 
   /**
diff --git a/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php
index 0e01c23..2a435c9 100644
--- a/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php
+++ b/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php
@@ -132,7 +132,7 @@ public function testMigrateUpgrade() {
 
     // Use the driver connection form to get the correct options out of the
     // database settings. This supports all of the databases we test against.
-    $drivers = drupal_get_database_types();
+    $drivers = \Drupal::service('database.driver.discovery')->getInstallableDriversInstallers();
     $form = $drivers[$driver]->getFormOptions($connection_options);
     $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
     $edit = [
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
index 98c05aa..f15a0b3 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
@@ -134,7 +134,7 @@ public function testMigrateUpgrade() {
 
     // Use the driver connection form to get the correct options out of the
     // database settings. This supports all of the databases we test against.
-    $drivers = drupal_get_database_types();
+    $drivers = \Drupal::service('database.driver.discovery')->getInstallableDriversInstallers();
     $form = $drivers[$driver]->getFormOptions($connection_options);
     $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
     $version = $this->getLegacyDrupalVersion($this->sourceDatabase);
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 0e0ea2a..02ecf8f 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -316,9 +316,11 @@ function simpletest_phpunit_configuration_filepath() {
  */
 function simpletest_phpunit_run_command(array $unescaped_test_classnames, $phpunit_file, &$status = NULL, &$output = NULL) {
   global $base_url;
-  // Setup an environment variable containing the database connection so that
-  // functional tests can connect to the database.
-  putenv('SIMPLETEST_DB=' . Database::getConnectionInfoAsUrl());
+  if (Database::getConnectionInfo()) {
+    // Setup an environment variable containing the database connection so that
+    // functional tests can connect to the database.
+    putenv('SIMPLETEST_DB=' . Database::getConnectionInfoAsUrl());
+  }
 
   // Setup an environment variable containing the base URL, if it is available.
   // This allows functional tests to browse the site under test. When running
diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php
index 255adcc..a287710 100644
--- a/core/modules/simpletest/src/KernelTestBase.php
+++ b/core/modules/simpletest/src/KernelTestBase.php
@@ -212,9 +212,8 @@ protected function setUp() {
     $this->kernel->boot();
 
     // Ensure database install tasks have been run.
-    require_once __DIR__ . '/../../../includes/install.inc';
     $connection = Database::getConnection();
-    $errors = db_installer_object($connection->driver())->runTasks();
+    $errors = \Drupal::service('database.driver.discovery')->getInstaller($connection->driver())->runTasks();
     if (!empty($errors)) {
       $this->fail('Failed to run installer database tasks: ' . implode(', ', $errors));
     }
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
index 05719fb..743416e 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
+++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
@@ -325,11 +325,13 @@ protected function runDbTasks() {
     $container
       ->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
       ->addArgument(new Reference('language.default'));
+    $container
+      ->register('database.driver.discovery', 'Drupal\Core\Database\DatabaseDriverDiscovery')
+      ->addArgument(__DIR__ . '/../../../../../..');
     \Drupal::setContainer($container);
 
-    require_once __DIR__ . '/../../../../../includes/install.inc';
     $connection = Database::getConnection();
-    $errors = db_installer_object($connection->driver())->runTasks();
+    $errors = \Drupal::service('database.driver.discovery')->getInstaller($connection->driver())->runTasks();
     if (!empty($errors)) {
       $this->fail('Failed to run installer database tasks: ' . implode(', ', $errors));
     }
diff --git a/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php b/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php
index cb7f5eb..eff9f41 100644
--- a/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php
+++ b/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php
@@ -58,18 +58,16 @@ public function testSpecifyDatabaseDoesNotExist() {
    * Test supplying database connection as a url.
    */
   public function testSpecifyDbUrl() {
-    $connection_info = Database::getConnectionInfo('default')['default'];
-
     $command = new DbCommandBaseTester();
     $command_tester = new CommandTester($command);
     $command_tester->execute([
-      '-db-url' => $connection_info['driver'] . '://' . $connection_info['username'] . ':' . $connection_info['password'] . '@' . $connection_info['host'] . '/' . $connection_info['database']
+      '-db-url' => Database::getConnectionInfoAsUrl()
     ]);
     $this->assertEquals('db-tools', $command->getDatabaseConnection($command_tester->getInput())->getKey());
 
     Database::removeConnection('db-tools');
     $command_tester->execute([
-      '--database-url' => $connection_info['driver'] . '://' . $connection_info['username'] . ':' . $connection_info['password'] . '@' . $connection_info['host'] . '/' . $connection_info['database']
+      '--database-url' => Database::getConnectionInfoAsUrl()
     ]);
     $this->assertEquals('db-tools', $command->getDatabaseConnection($command_tester->getInput())->getKey());
   }
@@ -91,9 +89,8 @@ public function testPrefix() {
     ]);
     $this->assertEquals('extra', $command->getDatabaseConnection($command_tester->getInput())->tablePrefix());
 
-    $connection_info = Database::getConnectionInfo('default')['default'];
     $command_tester->execute([
-      '-db-url' => $connection_info['driver'] . '://' . $connection_info['username'] . ':' . $connection_info['password'] . '@' . $connection_info['host'] . '/' . $connection_info['database'],
+      '-db-url' => Database::getConnectionInfoAsUrl(),
       '--prefix' => 'extra2',
     ]);
     $this->assertEquals('extra2', $command->getDatabaseConnection($command_tester->getInput())->tablePrefix());
diff --git a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
index 4aca500..c1fe2ea 100644
--- a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
@@ -161,6 +161,11 @@ protected function setUp() {
     $kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
     $kernel->loadLegacyIncludes();
 
+    $container = new ContainerBuilder();
+    $container
+      ->register('database.driver.discovery', 'Drupal\Core\Database\DatabaseDriverDiscovery')
+      ->addArgument($this->root);
+    \Drupal::setContainer($container);
     $this->changeDatabasePrefix();
     $this->runDbTasks();
     // Allow classes to set database dump files.
@@ -400,11 +405,13 @@ protected function runDbTasks() {
     $container
       ->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
       ->addArgument(new Reference('language.default'));
+    $container
+      ->register('database.driver.discovery', 'Drupal\Core\Database\DatabaseDriverDiscovery')
+      ->addArgument($this->root);
     \Drupal::setContainer($container);
 
-    require_once __DIR__ . '/../../../../includes/install.inc';
     $connection = Database::getConnection();
-    $errors = db_installer_object($connection->driver())->runTasks();
+    $errors = \Drupal::service('database.driver.discovery')->getInstaller($connection->driver())->runTasks();
     if (!empty($errors)) {
       $this->fail('Failed to run installer database tasks: ' . implode(', ', $errors));
     }
diff --git a/core/tests/Drupal/KernelTests/Core/Database/DatabaseDriverDiscoveryTest.php b/core/tests/Drupal/KernelTests/Core/Database/DatabaseDriverDiscoveryTest.php
new file mode 100644
index 0000000..834e9ab
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Database/DatabaseDriverDiscoveryTest.php
@@ -0,0 +1,112 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Database;
+
+use Drupal\Core\Database\DatabaseDriverDiscovery;
+use Drupal\Core\Database\Driver\mysql\Install\Tasks as MySqlTasks;
+use Drupal\Core\Database\Driver\sqlite\Install\Tasks as SqliteTasks;
+use Drupal\Core\Database\Driver\pgsql\Install\Tasks as PgSqlTasks;
+
+/**
+ * Tests the DatabaseDriverDiscovery class.
+ *
+ * @coversDefaultClass \Drupal\Core\Database\DatabaseDriverDiscovery
+ * @group Database
+ */
+class DatabaseDriverDiscoveryTest extends DatabaseTestBase {
+
+  /**
+   * Mocked DatabaseDriverDiscovery object.
+   *
+   * @var \Drupal\Core\Database\DatabaseDriverDiscovery
+   */
+  protected $databaseDriverDiscovery;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    // Get a mock of the DatabaseDriverDiscovery, where the discovery locations
+    // are overridden. We add discovering the test Stub driver defined in the
+    // Database unit test namespace.
+    $mock_builder = $this->getMockBuilder(DatabaseDriverDiscovery::class);
+    $this->databaseDriverDiscovery = $mock_builder
+      ->disableOriginalConstructor()
+      ->setMethods(['getDiscoveryLocations'])
+      ->getMock();
+    $this->databaseDriverDiscovery
+      ->expects($this->any())
+      ->method('getDiscoveryLocations')
+      ->will($this->returnValue([
+        'Drupal\\Core\\Database\\Driver' => __DIR__ . '/../../../../../lib/Drupal/Core/Database/Driver',
+        'Drupal\\Tests\\Core\\Database' => __DIR__ . '/../../../Tests/Core/Database',
+      ]));
+  }
+
+  /**
+   * @covers ::getInstallableDriversInstallerNames
+   */
+  public function testGetInstallableDriversInstallerNames() {
+    $installable_drivers_installers_names = $this->databaseDriverDiscovery->getInstallableDriversInstallerNames();
+
+    // We cannot assume all the core drivers will be installable during a
+    // test run. Assert names conditionally based on whether they are.
+    if (isset($installable_drivers_installers_names['mysql'])) {
+      $this->assertEquals('MySQL, MariaDB, Percona Server, or equivalent', $installable_drivers_installers_names['mysql']);
+    }
+    if (isset($installable_drivers_installers_names['sqlite'])) {
+      $this->assertEquals('SQLite', $installable_drivers_installers_names['sqlite']);
+    }
+    if (isset($installable_drivers_installers_names['pgsql'])) {
+      $this->assertEquals('PostgreSQL', $installable_drivers_installers_names['pgsql']);
+    }
+
+    // The 'Stub' driver is not installable.
+    $this->assertArrayNotHasKey('Stub', $installable_drivers_installers_names);
+  }
+
+  /**
+   * @covers ::getInstallableDriversInstallers
+   */
+  public function testGetInstallableDriversInstallers() {
+    $installable_drivers_installers = $this->databaseDriverDiscovery->getInstallableDriversInstallers();
+
+    // We cannot assume all the core drivers will be installable during a
+    // test run. Assert classes conditionally based on whether they are.
+    if (isset($installable_drivers_installers['mysql'])) {
+      $this->assertInstanceOf(MySqlTasks::class, $installable_drivers_installers['mysql']);
+    }
+    if (isset($installable_drivers_installers['sqlite'])) {
+      $this->assertInstanceOf(SqliteTasks::class, $installable_drivers_installers['sqlite']);
+    }
+    if (isset($installable_drivers_installers['pgsql'])) {
+      $this->assertInstanceOf(PgSqlTasks::class, $installable_drivers_installers['pgsql']);
+    }
+
+    // The 'Stub' driver is not installable.
+    $this->assertArrayNotHasKey('Stub', $installable_drivers_installers);
+  }
+
+  /**
+   * @covers ::discoverDatabaseDrivers
+   */
+  public function testDiscoverDatabaseDrivers() {
+    $drivers = $this->databaseDriverDiscovery->discoverDatabaseDrivers();
+
+    // Core drivers and the 'Stub' one should have been discovered regardless
+    // whether they are installable or not.
+    $this->assertArrayHasKey('mysql', $drivers);
+    $this->assertArrayHasKey('pgsql', $drivers);
+    $this->assertArrayHasKey('sqlite', $drivers);
+    $this->assertArrayHasKey('Stub', $drivers);
+
+    // The 'Stub' driver is not installable.
+    $this->assertFalse($drivers['Stub']['installable']);
+
+    // The 'Stub' driver installer has a name.
+    $this->assertEquals('Stub database for testing', $drivers['Stub']['installer']->name());
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/KernelTestBase.php b/core/tests/Drupal/KernelTests/KernelTestBase.php
index ca1a517..dd50eef 100644
--- a/core/tests/Drupal/KernelTests/KernelTestBase.php
+++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
@@ -263,6 +263,11 @@ protected function bootEnvironment() {
     require_once $this->root . '/core/includes/bootstrap.inc';
 
     // Set up virtual filesystem.
+    $container = new ContainerBuilder();
+    $container
+      ->register('database.driver.discovery', 'Drupal\Core\Database\DatabaseDriverDiscovery')
+      ->addArgument($this->root);
+    \Drupal::setContainer($container);
     Database::addConnectionInfo('default', 'test-runner', $this->getDatabaseConnectionInfo()['default']);
     $test_db = new TestDatabase();
     $this->siteDirectory = $test_db->getTestSitePath();
@@ -371,9 +376,8 @@ private function bootKernel() {
     $this->container = $kernel->getContainer();
 
     // Ensure database tasks have been run.
-    require_once __DIR__ . '/../../../includes/install.inc';
     $connection = Database::getConnection();
-    $errors = db_installer_object($connection->driver())->runTasks();
+    $errors = \Drupal::service('database.driver.discovery')->getInstaller($connection->driver())->runTasks();
     if (!empty($errors)) {
       $this->fail('Failed to run installer database tasks: ' . implode(', ', $errors));
     }
@@ -462,7 +466,7 @@ protected function getDatabaseConnectionInfo() {
         // Replace the full table prefix definition to ensure that no table
         // prefixes of the test runner leak into the test.
         $connection_info[$target]['prefix'] = [
-          'default' => $value['prefix']['default'] . $this->databasePrefix,
+          'default' => $this->databasePrefix,
         ];
       }
     }
diff --git a/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php b/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php
index e455847..74e30ae 100644
--- a/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php
+++ b/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\Tests\Core\Database;
 
-use Drupal\Tests\Core\Database\Stub\StubConnection;
+use Drupal\Tests\Core\Database\Stub\Connection;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -46,10 +46,10 @@ public function providerPrefixRoundTrip() {
    */
   public function testPrefixRoundTrip($expected, $prefix_info) {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    $connection = new StubConnection($mock_pdo, []);
+    $connection = new Connection($mock_pdo, []);
 
     // setPrefix() is protected, so we make it accessible with reflection.
-    $reflection = new \ReflectionClass('Drupal\Tests\Core\Database\Stub\StubConnection');
+    $reflection = new \ReflectionClass('Drupal\Tests\Core\Database\Stub\Connection');
     $set_prefix = $reflection->getMethod('setPrefix');
     $set_prefix->setAccessible(TRUE);
 
@@ -95,7 +95,7 @@ public function providerTestPrefixTables() {
    */
   public function testPrefixTables($expected, $prefix_info, $query) {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    $connection = new StubConnection($mock_pdo, ['prefix' => $prefix_info]);
+    $connection = new Connection($mock_pdo, ['prefix' => $prefix_info]);
     $this->assertEquals($expected, $connection->prefixTables($query));
   }
 
@@ -129,7 +129,7 @@ public function providerEscapeMethods() {
    */
   public function testEscapeMethods($expected, $name) {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    $connection = new StubConnection($mock_pdo, []);
+    $connection = new Connection($mock_pdo, []);
     $this->assertEquals($expected, $connection->escapeDatabase($name));
     $this->assertEquals($expected, $connection->escapeTable($name));
     $this->assertEquals($expected, $connection->escapeField($name));
@@ -173,7 +173,7 @@ public function providerGetDriverClass() {
    */
   public function testGetDriverClass($expected, $namespace, $class) {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    $connection = new StubConnection($mock_pdo, ['namespace' => $namespace]);
+    $connection = new Connection($mock_pdo, ['namespace' => $namespace]);
     // Set the driver using our stub class' public property.
     $this->assertEquals($expected, $connection->getDriverClass($class));
   }
@@ -204,7 +204,7 @@ public function providerSchema() {
    */
   public function testSchema($expected, $driver, $namespace) {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    $connection = new StubConnection($mock_pdo, ['namespace' => $namespace]);
+    $connection = new Connection($mock_pdo, ['namespace' => $namespace]);
     $connection->driver = $driver;
     $this->assertInstanceOf($expected, $connection->schema());
   }
@@ -214,9 +214,9 @@ public function testSchema($expected, $driver, $namespace) {
    */
   public function testDestroy() {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    // Mocking StubConnection gives us access to the $schema attribute.
+    // Mocking Connection gives us access to the $schema attribute.
     $connection = $this->getMock(
-      'Drupal\Tests\Core\Database\Stub\StubConnection',
+      'Drupal\Tests\Core\Database\Stub\Connection',
       NULL,
       [$mock_pdo, ['namespace' => 'Drupal\\Tests\\Core\\Database\\Stub\\Driver']]
     );
@@ -261,7 +261,7 @@ public function providerMakeComments() {
    */
   public function testMakeComments($expected, $comment_array) {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    $connection = new StubConnection($mock_pdo, []);
+    $connection = new Connection($mock_pdo, []);
     $this->assertEquals($expected, $connection->makeComment($comment_array));
   }
 
@@ -288,10 +288,10 @@ public function providerFilterComments() {
    */
   public function testFilterComments($expected, $comment) {
     $mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
-    $connection = new StubConnection($mock_pdo, []);
+    $connection = new Connection($mock_pdo, []);
 
     // filterComment() is protected, so we make it accessible with reflection.
-    $reflection = new \ReflectionClass('Drupal\Tests\Core\Database\Stub\StubConnection');
+    $reflection = new \ReflectionClass('Drupal\Tests\Core\Database\Stub\Connection');
     $filter_comment = $reflection->getMethod('filterComment');
     $filter_comment->setAccessible(TRUE);
 
diff --git a/core/tests/Drupal/Tests/Core/Database/Stub/Connection.php b/core/tests/Drupal/Tests/Core/Database/Stub/Connection.php
new file mode 100644
index 0000000..06500f7
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Database/Stub/Connection.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Drupal\Tests\Core\Database\Stub;
+
+use Drupal\Core\Database\Connection as DatabaseConnection;
+use Drupal\Core\Database\StatementEmpty;
+
+/**
+ * A stub of the abstract Connection class for testing purposes.
+ *
+ * Includes minimal implementations of Connection's abstract methods.
+ */
+class Connection extends DatabaseConnection {
+
+  /**
+   * Public property so we can test driver loading mechanism.
+   *
+   * @var string
+   * @see driver().
+   */
+  public $driver = 'stub';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function queryRange($query, $from, $count, array $args = [], array $options = []) {
+    return new StatementEmpty();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function queryTemporary($query, array $args = [], array $options = []) {
+    return '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function driver() {
+    return $this->driver;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function databaseType() {
+    return 'stub';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createDatabase($database) {
+    return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function mapConditionOperator($operator) {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function nextId($existing_id = 0) {
+    return 0;
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Database/Stub/Install/Tasks.php b/core/tests/Drupal/Tests/Core/Database/Stub/Install/Tasks.php
new file mode 100644
index 0000000..6b0d733
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Database/Stub/Install/Tasks.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Tests\Core\Database\Stub\Install;
+
+use Drupal\Core\Database\Install\Tasks as InstallTasks;
+
+/**
+ * A stub of the abstract Install\Tasks class for testing purposes.
+ */
+class Tasks extends InstallTasks {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function installable() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function name() {
+    return t('Stub database for testing');
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Database/Stub/StubConnection.php b/core/tests/Drupal/Tests/Core/Database/Stub/StubConnection.php
deleted file mode 100644
index 4692dff..0000000
--- a/core/tests/Drupal/Tests/Core/Database/Stub/StubConnection.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-namespace Drupal\Tests\Core\Database\Stub;
-
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Database\StatementEmpty;
-
-/**
- * A stub of the abstract Connection class for testing purposes.
- *
- * Includes minimal implementations of Connection's abstract methods.
- */
-class StubConnection extends Connection {
-
-  /**
-   * Public property so we can test driver loading mechanism.
-   *
-   * @var string
-   * @see driver().
-   */
-  public $driver = 'stub';
-
-  /**
-   * {@inheritdoc}
-   */
-  public function queryRange($query, $from, $count, array $args = [], array $options = []) {
-    return new StatementEmpty();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function queryTemporary($query, array $args = [], array $options = []) {
-    return '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function driver() {
-    return $this->driver;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function databaseType() {
-    return 'stub';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function createDatabase($database) {
-    return;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function mapConditionOperator($operator) {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function nextId($existing_id = 0) {
-    return 0;
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/Core/Database/UrlConversionTest.php b/core/tests/Drupal/Tests/Core/Database/UrlConversionTest.php
index c514b2e..2e56e0f 100644
--- a/core/tests/Drupal/Tests/Core/Database/UrlConversionTest.php
+++ b/core/tests/Drupal/Tests/Core/Database/UrlConversionTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\Core\Database;
 
 use Drupal\Core\Database\Database;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -13,6 +14,18 @@
 class UrlConversionTest extends UnitTestCase {
 
   /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $container = new ContainerBuilder();
+    $container
+      ->register('database.driver.discovery', 'Drupal\Core\Database\DatabaseDriverDiscovery')
+      ->addArgument(__DIR__ . '/../../../../../..');
+    \Drupal::setContainer($container);
+  }
+
+  /**
    * @covers ::convertDbUrlToConnectionInfo
    *
    * @dataProvider providerConvertDbUrlToConnectionInfo
@@ -37,21 +50,21 @@ public function providerConvertDbUrlToConnectionInfo() {
     $url1 = 'mysql://test_user:test_pass@test_host:3306/test_database';
     $database_array1 = [
       'driver' => 'mysql',
-      'username' => 'test_user',
-      'password' => 'test_pass',
       'host' => 'test_host',
       'database' => 'test_database',
-      'port' => '3306',
+      'prefix' => NULL,
+      'port' => 3306,
+      'username' => 'test_user',
+      'password' => 'test_pass',
+      'namespace' => 'Drupal\Core\Database\Driver\mysql',
     ];
     $root2 = '/var/www/d8';
     $url2 = 'sqlite://test_user:test_pass@test_host:3306/test_database';
     $database_array2 = [
       'driver' => 'sqlite',
-      'username' => 'test_user',
-      'password' => 'test_pass',
-      'host' => 'test_host',
       'database' => $root2 . '/test_database',
-      'port' => 3306,
+      'prefix' => NULL,
+      'namespace' => 'Drupal\Core\Database\Driver\sqlite',
     ];
     return [
       [$root1, $url1, $database_array1],
@@ -122,7 +135,6 @@ public function providerGetConnectionInfoAsUrl() {
       'prefix' => '',
       'host' => 'test_host',
       'port' => '3306',
-      'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
       'driver' => 'mysql',
     ];
     $expected_url1 = 'mysql://test_user:test_pass@test_host:3306/test_database';
