diff --git a/core/includes/database.inc b/core/includes/database.inc
index 1b133263eb..e90616f532 100644
--- a/core/includes/database.inc
+++ b/core/includes/database.inc
@@ -54,11 +54,9 @@
  * @see \Drupal\Core\Database\Connection::defaultOptions()
  */
 function db_query($query, array $args = [], array $options = []) {
-  if (empty($options['target'])) {
-    $options['target'] = 'default';
-  }
-
-  return Database::getConnection($options['target'])->query($query, $args, $options);
+  $target = empty($options['target']) ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->query($query, $args, $options);
 }
 
 /**
@@ -93,11 +91,9 @@ function db_query($query, array $args = [], array $options = []) {
  */
 function db_query_range($query, $from, $count, array $args = [], array $options = []) {
   @trigger_error('db_query_range() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call queryRange() on it. For example, $injected_database->queryRange($query, $from, $count, $args, $options). See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  if (empty($options['target'])) {
-    $options['target'] = 'default';
-  }
-
-  return Database::getConnection($options['target'])->queryRange($query, $from, $count, $args, $options);
+  $target = empty($options['target']) ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->queryRange($query, $from, $count, $args, $options);
 }
 
 /**
@@ -130,11 +126,9 @@ function db_query_range($query, $from, $count, array $args = [], array $options
  */
 function db_query_temporary($query, array $args = [], array $options = []) {
   @trigger_error('db_query_temporary() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call queryTemporary() on it. For example, $injected_database->queryTemporary($query, $args, $options). See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  if (empty($options['target'])) {
-    $options['target'] = 'default';
-  }
-
-  return Database::getConnection($options['target'])->queryTemporary($query, $args, $options);
+  $target = empty($options['target']) ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->queryTemporary($query, $args, $options);
 }
 
 /**
@@ -158,10 +152,9 @@ function db_query_temporary($query, array $args = [], array $options = []) {
  */
 function db_insert($table, array $options = []) {
   @trigger_error('db_insert() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call insert() on it. For example, $injected_database->insert($table, $options); See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  if (empty($options['target']) || $options['target'] == 'replica') {
-    $options['target'] = 'default';
-  }
-  return Database::getConnection($options['target'])->insert($table, $options);
+  $target = empty($options['target']) || $options['target'] == 'replica' ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->insert($table, $options);
 }
 
 /**
@@ -185,12 +178,9 @@ function db_insert($table, array $options = []) {
  */
 function db_merge($table, array $options = []) {
   @trigger_error('db_merge() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call merge() on it. For example, $injected_database->merge($table, $options). See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  // @todo Move away from here setting default target connection,
-  // https://www.drupal.org/node/2947775
-  if (empty($options['target']) || $options['target'] == 'replica') {
-    $options['target'] = 'default';
-  }
-  return Database::getConnection($options['target'])->merge($table, $options);
+  $target = empty($options['target']) || $options['target'] == 'replica' ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->merge($table, $options);
 }
 
 /**
@@ -214,10 +204,9 @@ function db_merge($table, array $options = []) {
  */
 function db_update($table, array $options = []) {
   @trigger_error('db_update() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call call update() on it. For example, $injected_database->update($table, $options); See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  if (empty($options['target']) || $options['target'] == 'replica') {
-    $options['target'] = 'default';
-  }
-  return Database::getConnection($options['target'])->update($table, $options);
+  $target = empty($options['target']) || $options['target'] == 'replica' ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->update($table, $options);
 }
 
 /**
@@ -241,12 +230,9 @@ function db_update($table, array $options = []) {
  */
 function db_delete($table, array $options = []) {
   @trigger_error('db_delete is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call delete() on it. For example, $injected_database->delete($table, $options). See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  // @todo Move away from here setting default target connection,
-  // https://www.drupal.org/node/2947775
-  if (empty($options['target']) || $options['target'] == 'replica') {
-    $options['target'] = 'default';
-  }
-  return Database::getConnection($options['target'])->delete($table, $options);
+  $target = empty($options['target']) || $options['target'] == 'replica' ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->delete($table, $options);
 }
 
 /**
@@ -270,10 +256,9 @@ function db_delete($table, array $options = []) {
  */
 function db_truncate($table, array $options = []) {
   @trigger_error('db_truncate() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call truncate() on it. For example, $injected_database->truncate($table, $options). See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  if (empty($options['target']) || $options['target'] == 'replica') {
-    $options['target'] = 'default';
-  }
-  return Database::getConnection($options['target'])->truncate($table, $options);
+  $target = empty($options['target']) || $options['target'] == 'replica' ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->truncate($table, $options);
 }
 
 /**
@@ -301,10 +286,9 @@ function db_truncate($table, array $options = []) {
  */
 function db_select($table, $alias = NULL, array $options = []) {
   @trigger_error('db_select() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call call select() on it. For example, $injected_database->db_select($table, $alias, $options); See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  if (empty($options['target'])) {
-    $options['target'] = 'default';
-  }
-  return Database::getConnection($options['target'])->select($table, $alias, $options);
+  $target = empty($options['target']) ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->select($table, $alias, $options);
 }
 
 /**
@@ -329,12 +313,9 @@ function db_select($table, $alias = NULL, array $options = []) {
  */
 function db_transaction($name = NULL, array $options = []) {
   @trigger_error('db_transaction is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get a database connection injected into your service from the container and call startTransaction() on it. For example, $injected_database->startTransaction($name). See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
-  // @todo Move away from here setting default target connection,
-  // https://www.drupal.org/node/2947775
-  if (empty($options['target'])) {
-    $options['target'] = 'default';
-  }
-  return Database::getConnection($options['target'])->startTransaction($name);
+  $target = empty($options['target']) ? 'default' : $options['target'];
+  unset($options['target']);
+  return Database::getConnection($target)->startTransaction($name);
 }
 
 /**
@@ -473,10 +454,9 @@ function db_driver() {
  */
 function db_close(array $options = []) {
   @trigger_error('db_close() is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Use \Drupal\Core\Database\Database::closeConnection() instead. See https://www.drupal.org/node/2993033.', E_USER_DEPRECATED);
-  if (empty($options['target'])) {
-    $options['target'] = NULL;
-  }
-  Database::closeConnection($options['target']);
+  $target = empty($options['target']) ? 'default' : $options['target'];
+  unset($options['target']);
+  Database::closeConnection($target);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php
index eaba227db2..3a0c278c4e 100644
--- a/core/lib/Drupal/Core/Database/Connection.php
+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -212,12 +212,6 @@ public function destroy() {
    *
    * A given query can be customized with a number of option flags in an
    * associative array:
-   * - target: The database "target" against which to execute a query. Valid
-   *   values are "default" or "replica". The system will first try to open a
-   *   connection to a database specified with the user-supplied key. If one
-   *   is not available, it will silently fall back to the "default" target.
-   *   If multiple databases connections are specified with the same target,
-   *   one will be selected at random for the duration of the request.
    * - fetch: This element controls how rows from a result set will be
    *   returned. Legal values include PDO::FETCH_ASSOC, PDO::FETCH_BOTH,
    *   PDO::FETCH_OBJ, PDO::FETCH_NUM, or a string representing the name of a
@@ -260,7 +254,6 @@ public function destroy() {
    */
   protected function defaultOptions() {
     return [
-      'target' => 'default',
       'fetch' => \PDO::FETCH_OBJ,
       'return' => Database::RETURN_STATEMENT,
       'throw_exception' => TRUE,
@@ -600,6 +593,9 @@ protected function filterComment($comment = '') {
   public function query($query, array $args = [], $options = []) {
     // Use default values if not already set.
     $options += $this->defaultOptions();
+    if (isset($options['target'])) {
+      @trigger_error('Passing a \'target\' key to Connection::query $options argument is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get the target connection via Database::getConnection() passing the target in input and execute query() on it. See https://www.drupal.org/node/2993033', E_USER_DEPRECATED);
+    }
 
     try {
       // We allow either a pre-bound statement object or a literal string.
diff --git a/core/tests/Drupal/KernelTests/Core/Database/DatabaseLegacyTest.php b/core/tests/Drupal/KernelTests/Core/Database/DatabaseLegacyTest.php
index 3125da8cff..7a29b34583 100644
--- a/core/tests/Drupal/KernelTests/Core/Database/DatabaseLegacyTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Database/DatabaseLegacyTest.php
@@ -428,6 +428,15 @@ public function testDbTruncate() {
     $this->assertInstanceOf(Truncate::class, db_truncate('test'));
   }
 
+  /**
+   * Tests deprecation of the $options 'target' key in Connection::query.
+   *
+   * @expectedDeprecation Passing a 'target' key to Connection::query $options argument is deprecated in Drupal 8.0.x and will be removed before Drupal 9.0.0. Instead, get the target connection via Database::getConnection() passing the target in input and execute query() on it. https://www.drupal.org/node/2993033
+   */
+  public function testDbOptionsTarget() {
+    $this->assertNotNull($this->connection->query('SELECT * FROM {test}', [], ['target' => 'bar']));
+  }
+
   /**
    * Tests deprecation of the db_query_temporary() function.
    *
