diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index c4b0cb4..c1a9dd1 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -566,7 +566,7 @@ function drupal_settings_initialize() {
   global $base_url, $base_path, $base_root, $script_path;
 
   // Export these settings.php variables to the global namespace.
-  global $databases, $cookie_domain, $conf, $db_prefix, $drupal_hash_salt, $base_secure_url, $base_insecure_url, $config_directories;
+  global $cookie_domain, $conf, $db_prefix, $drupal_hash_salt, $base_secure_url, $base_insecure_url, $config_directories;
   $conf = array();
 
   // Make conf_path() available as local variable in settings.php.
@@ -576,6 +576,8 @@ function drupal_settings_initialize() {
   }
   require_once __DIR__ . '../../lib/Drupal/Component/Utility/Settings.php';
 
+  Database::setConnectionInfo($databases);
+
   new Settings(isset($settings) ? $settings : array());
   $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
 
@@ -1893,10 +1895,13 @@ function drupal_get_user_timezone() {
  *   A salt based on information in settings.php, not in the database.
  */
 function drupal_get_hash_salt() {
-  global $drupal_hash_salt, $databases;
-  // If the $drupal_hash_salt variable is empty, a hash of the serialized
-  // database credentials is used as a fallback salt.
-  return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
+  global $drupal_hash_salt;
+  // This should never happen, as it breaks user logins and many other services.
+  // Therefore, explicitly notify the user (developer) by throwing an exception.
+  if (empty($drupal_hash_salt)) {
+    throw new \RuntimeException('Missing $drupal_hash_salt in settings.php.');
+  }
+  return $drupal_hash_salt;
 }
 
 /**
@@ -1977,7 +1982,7 @@ function _drupal_bootstrap_configuration() {
   // Redirect the user to the installation script if Drupal has not been
   // installed yet (i.e., if no $databases array has been defined in the
   // settings.php file) and we are not already installing.
-  if (empty($GLOBALS['databases']) && !drupal_installation_attempted() && !drupal_is_cli()) {
+  if (!Database::getConnectionInfo() && !drupal_installation_attempted() && !drupal_is_cli()) {
     include_once __DIR__ . '/install.inc';
     install_goto('core/install.php');
   }
@@ -2058,7 +2063,8 @@ function _drupal_initialize_db_test_prefix() {
     $test_info['test_run_id'] = $test_prefix;
     $test_info['in_child_site'] = TRUE;
 
-    foreach ($GLOBALS['databases']['default'] as &$value) {
+    $database = Database::getConnectionInfo();
+    $value = &$database;
       // Extract the current default database prefix.
       if (!isset($value['prefix'])) {
         $current_prefix = '';
@@ -2074,7 +2080,8 @@ function _drupal_initialize_db_test_prefix() {
       $value['prefix'] = array(
         'default' => $current_prefix . $test_prefix,
       );
-    }
+    Database::removeConnection('default');
+    Database::addConnectionInfo('default', 'default', $database);
   }
 }
 
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 5a46c8c..912894d 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -513,7 +513,7 @@ function install_begin_request(&$install_state) {
     $task = NULL;
 
     // Do not install over a configured settings.php.
-    if (!empty($GLOBALS['databases'])) {
+    if (Database::getConnectionInfo()) {
       throw new Exception(install_already_done_error());
     }
   }
@@ -1065,8 +1065,7 @@ function install_verify_completed_task() {
  * Verifies that settings.php specifies a valid database connection.
  */
 function install_verify_database_settings() {
-  global $databases;
-  if (!empty($databases)) {
+  if ($databases = Database::getConnectionInfo()) {
     $database = $databases['default']['default'];
     drupal_static_reset('conf_path');
     $settings_file = './' . conf_path(FALSE) . '/settings.php';
@@ -1089,12 +1088,10 @@ function install_verify_database_settings() {
  * @ingroup forms
  */
 function install_settings_form($form, &$form_state, &$install_state) {
-  global $databases;
-
   drupal_static_reset('conf_path');
   $conf_path = './' . conf_path(FALSE);
   $settings_file = $conf_path . '/settings.php';
-  $database = isset($databases['default']['default']) ? $databases['default']['default'] : array();
+  $database = Database::getConnectionInfo();
 
   drupal_set_title(t('Database configuration'));
 
@@ -1157,7 +1154,9 @@ function install_settings_form_validate($form, &$form_state) {
   // the test prefix.
   if ($test_prefix = drupal_valid_test_ua()) {
     $database['prefix'] = $test_prefix;
-    $database['password'] = $GLOBALS['databases']['default']['default']['password'];
+    // @todo Unresolvable environment data leakage.
+    // @see https://drupal.org/node/2171683
+    #$database['password'] = $GLOBALS['databases']['default']['default']['password'];
   }
   $drivers = drupal_get_database_types();
   $reflection = new \ReflectionClass($drivers[$driver]);
@@ -1184,7 +1183,6 @@ function install_settings_form_validate($form, &$form_state) {
  * Checks a database connection and returns any errors.
  */
 function install_database_errors($database, $settings_file) {
-  global $databases;
   $errors = array();
 
   // Check database type.
@@ -1196,18 +1194,13 @@ function install_database_errors($database, $settings_file) {
   else {
     // Run driver specific validation
     $errors += $database_types[$driver]->validateDatabaseSettings($database);
-
+    if (!empty($errors)) {
+      // No point to try further.
+      return $errors;
+    }
     // Run tasks associated with the database type. Any errors are caught in the
     // calling function.
-    $databases['default']['default'] = $database;
-    // Just changing the global doesn't get the new information processed.
-    // We need to close any active connections and tell the Database class to
-    // re-parse $databases.
-    if (Database::isActiveConnection()) {
-      Database::closeConnection();
-    }
-    Database::parseConnectionInfo();
-
+    Database::addConnectionInfo('default', 'default', $database);
     try {
       db_run_tasks($driver);
     }
@@ -1239,17 +1232,19 @@ function install_settings_form_submit($form, &$form_state) {
   // salt is used to verify the validity of the automated test browser.
   // Because of these, there's a little difference in the code following but
   // it is small and self-contained.
-  if ($test_prefix = drupal_valid_test_ua()) {
-    foreach ($form_state['storage']['database'] as $k => $v) {
-      if ($k != 'password') {
-        $settings['databases']['default']['default'][$k] = (object) array(
-          'value'    => $v,
-          'required' => TRUE,
-        );
-      }
-    }
-  }
-  else {
+  // @todo Unresolvable environment data leakage.
+  // @see https://drupal.org/node/2171683
+//  if ($test_prefix = drupal_valid_test_ua()) {
+//    foreach ($form_state['storage']['database'] as $k => $v) {
+//      if ($k != 'password') {
+//        $settings['databases']['default']['default'][$k] = (object) array(
+//          'value'    => $v,
+//          'required' => TRUE,
+//        );
+//      }
+//    }
+//  }
+//  else {
     $settings['databases']['default']['default'] = (object) array(
       'value'    => $database,
       'required' => TRUE,
@@ -1258,7 +1253,7 @@ function install_settings_form_submit($form, &$form_state) {
       'value'    => Crypt::randomStringHashed(55),
       'required' => TRUE,
     );
-  }
+//  }
 
   // Remember the profile which was used.
   $settings['settings'] = array(
diff --git a/core/lib/Drupal/Core/Database/Database.php b/core/lib/Drupal/Core/Database/Database.php
index e3eaa6e..77b565c 100644
--- a/core/lib/Drupal/Core/Database/Database.php
+++ b/core/lib/Drupal/Core/Database/Database.php
@@ -48,6 +48,13 @@
   static protected $connections = array();
 
   /**
+   * The unprocessed database connection information from settings.php.
+   *
+   * @var array
+   */
+  static protected $rawDatabaseInfo = NULL;
+
+  /**
    * A processed copy of the database connection information from settings.php.
    *
    * @var array
@@ -194,6 +201,9 @@
    *   The previous database connection key.
    */
   final public static function setActiveConnection($key = 'default') {
+    if (empty(self::$rawDatabaseInfo)) {
+      return;
+    }
     if (empty(self::$databaseInfo)) {
       self::parseConnectionInfo();
     }
@@ -209,9 +219,7 @@
    * Process the configuration file for database information.
    */
   final public static function parseConnectionInfo() {
-    global $databases;
-
-    $database_info = is_array($databases) ? $databases : array();
+    $database_info = self::getConnectionInfo();
     foreach ($database_info as $index => $info) {
       foreach ($database_info[$index] as $target => $value) {
         // If there is no "driver" property, then we assume it's an array of
@@ -237,10 +245,9 @@
       }
     }
 
-    if (!is_array(self::$databaseInfo)) {
+    if (!isset(self::$databaseInfo)) {
       self::$databaseInfo = $database_info;
     }
-
     // Merge the new $database_info into the existing.
     // array_merge_recursive() cannot be used, as it would make multiple
     // database, user, and password keys in the same database array.
@@ -274,6 +281,8 @@
    *   database driver it is connecting to.
    */
   public static function addConnectionInfo($key, $target, $info) {
+    // @todo $info is not necessarily processed yet, but other code only checks
+    //   for empty(self::$databaseInfo).
     if (empty(self::$databaseInfo[$key][$target])) {
       self::$databaseInfo[$key][$target] = $info;
     }
@@ -282,17 +291,38 @@ public static function addConnectionInfo($key, $target, $info) {
   /**
    * Gets information on the specified database connection.
    *
-   * @param $connection
-   *   The connection key for which we want information.
+   * @param $key
+   *   (optional) The connection key for which we want information.
+   * @param $target
+   *   (optional) The database target name.
+   *
+   * @return array
    */
-  final public static function getConnectionInfo($key = 'default') {
+  final public static function getConnectionInfo($key = 'default', $target = 'default') {
+    if (empty(self::$rawDatabaseInfo)) {
+      return array();
+    }
     if (empty(self::$databaseInfo)) {
       self::parseConnectionInfo();
     }
 
+    if (!empty(self::$databaseInfo[$key][$target])) {
+      return self::$databaseInfo[$key][$target];
+    }
     if (!empty(self::$databaseInfo[$key])) {
       return self::$databaseInfo[$key];
     }
+    return array();
+  }
+
+  /**
+   * Sets database connection information.
+   *
+   * @param array $databases
+   *   A multi-dimensional array specifying database connection parameters.
+   */
+  final public static function setConnectionInfo(array $databases) {
+    self::$rawDatabaseInfo = $databases;
   }
 
   /**
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 669c615..4719b8d 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -875,14 +875,6 @@ protected function changeDatabasePrefix() {
     }
     Database::addConnectionInfo('default', 'default', $connection_info['default']);
 
-    // Additionally override global $databases, since the installer does not use
-    // the Database connection info.
-    // @see install_verify_database_settings()
-    // @see install_database_errors()
-    // @todo Fix installer to use Database connection info.
-    global $databases;
-    $databases['default']['default'] = $connection_info['default'];
-
     // Indicate the database prefix was set up correctly.
     $this->setupDatabasePrefix = TRUE;
   }
@@ -1116,10 +1108,6 @@ protected function tearDown() {
     // Restore original database connection.
     Database::removeConnection('default');
     Database::renameConnection('simpletest_original_default', 'default');
-    // @see TestBase::changeDatabasePrefix()
-    global $databases;
-    $connection_info = Database::getConnectionInfo('default');
-    $databases['default']['default'] = $connection_info['default'];
 
     // Restore original globals.
     if (isset($this->originalThemeKey)) {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Database/ConnectionUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Database/ConnectionUnitTest.php
index 430a1b6..8029510 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Database/ConnectionUnitTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Database/ConnectionUnitTest.php
@@ -50,10 +50,7 @@ function setUp() {
 
     // Create an additional connection to monitor the connections being opened
     // and closed in this test.
-    // @see TestBase::changeDatabasePrefix()
     Database::addConnectionInfo('default', 'monitor', $connection_info['default']);
-    global $databases;
-    $databases['default']['monitor'] = $connection_info['default'];
     $this->monitor = Database::getConnection('monitor');
   }
 
