diff --git a/core/includes/database.inc b/core/includes/database.inc
index 98041cd..a7b2461 100644
--- a/core/includes/database.inc
+++ b/core/includes/database.inc
@@ -497,12 +497,11 @@ function db_field_exists($table, $field) {
 /**
  * Finds all tables that are like the specified base table name.
  *
- * @param $table_expression
- *   An SQL expression, for example "simpletest%" (without the quotes).
- *   BEWARE: this is not prefixed, the caller should take care of that.
+ * @param string $table_expression
+ *   An SQL expression, for example "cache_%" (without the quotes).
  *
- * @return
- *   Array, both the keys and the values are the matching tables.
+ * @return array
+ *   Both the keys and the values are the matching tables.
  */
 function db_find_tables($table_expression) {
   return Database::getConnection()->schema()->findTables($table_expression);
diff --git a/core/lib/Drupal/Core/Command/DbDumpCommand.php b/core/lib/Drupal/Core/Command/DbDumpCommand.php
index d71bb37..eeefeda 100644
--- a/core/lib/Drupal/Core/Command/DbDumpCommand.php
+++ b/core/lib/Drupal/Core/Command/DbDumpCommand.php
@@ -129,12 +129,9 @@ protected function generateScript() {
    *   An array of table names.
    */
   protected function getTables() {
-    $pattern = $this->connection->tablePrefix() . '%';
-    $tables = array_values($this->connection->schema()->findTables($pattern));
-    foreach ($tables as $key => $table) {
-      // The prefix is removed for the resultant script.
-      $table = $tables[$key] = str_replace($this->connection->tablePrefix(), '', $table);
+    $tables = array_values($this->connection->schema()->findTables('%'));
 
+    foreach ($tables as $key => $table) {
       // Remove any explicitly excluded tables.
       foreach ($this->excludeTables as $pattern) {
         if (preg_match('/^' . $pattern . '$/', $table)) {
@@ -142,6 +139,7 @@ protected function getTables() {
         }
       }
     }
+
     return $tables;
   }
 
diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php
index 7c42402..d0f53d4 100644
--- a/core/lib/Drupal/Core/Database/Connection.php
+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -175,7 +175,9 @@ public function destroy() {
     // Destroy all references to this connection by setting them to NULL.
     // The Statement class attribute only accepts a new value that presents a
     // proper callable, so we reset it to PDOStatement.
-    $this->connection->setAttribute(\PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array()));
+    if (!empty($this->statementClass)) {
+      $this->connection->setAttribute(\PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array()));
+    }
     $this->schema = NULL;
   }
 
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
index df5dcc9..55e9d34 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
@@ -154,9 +154,9 @@ public function __destruct() {
 
           // We can prune the database file if it doesn't have any tables.
           if ($count == 0) {
-            // Detach the database.
-            $this->query('DETACH DATABASE :schema', array(':schema' => $prefix));
-            // Destroy the database file.
+            // Detaching the database fails at this point, but no other queries
+            // are executed after the connection is destructed so we can simply
+            // remove the database file.
             unlink($this->connectionOptions['database'] . '-' . $prefix);
           }
         }
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
index 3ac3811..61bbeb9 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
@@ -694,14 +694,15 @@ public function fieldSetNoDefault($table, $field) {
   }
 
   public function findTables($table_expression) {
-    // Don't add the prefix, $table_expression already includes the prefix.
-    $info = $this->getPrefixInfo($table_expression, FALSE);
+    $info = $this->getPrefixInfo($table_expression);
 
     // Can't use query placeholders for the schema because the query would have
-    // to be :prefixsqlite_master, which does not work.
-    $result = db_query("SELECT name FROM " . $info['schema'] . ".sqlite_master WHERE type = :type AND name LIKE :table_name", array(
+    // to be :prefixsqlite_master, which does not work. We also need to ignore
+    // the internal SQLite tables.
+    $result = db_query("SELECT name FROM " . $info['schema'] . ".sqlite_master WHERE type = :type AND name LIKE :table_name AND name NOT LIKE :pattern", array(
       ':type' => 'table',
-      ':table_name' => $info['table'],
+      ':table_name' => $table_expression,
+      ':pattern' => 'sqlite_%',
     ));
     return $result->fetchAllKeyed(0, 0);
   }
diff --git a/core/lib/Drupal/Core/Database/Schema.php b/core/lib/Drupal/Core/Database/Schema.php
index 4ebfd40..8357650 100644
--- a/core/lib/Drupal/Core/Database/Schema.php
+++ b/core/lib/Drupal/Core/Database/Schema.php
@@ -16,6 +16,11 @@
  */
 abstract class Schema implements PlaceholderInterface {
 
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
   protected $connection;
 
   /**
@@ -175,23 +180,36 @@ public function tableExists($table) {
   /**
    * Find all tables that are like the specified base table name.
    *
-   * @param $table_expression
-   *   An SQL expression, for example "simpletest%" (without the quotes).
-   *   BEWARE: this is not prefixed, the caller should take care of that.
+   * @param string $table_expression
+   *   An SQL expression, for example "cache_%" (without the quotes).
    *
-   * @return
-   *   Array, both the keys and the values are the matching tables.
+   * @return array
+   *   Both the keys and the values are the matching tables.
    */
   public function findTables($table_expression) {
-    $condition = $this->buildTableNameCondition($table_expression, 'LIKE', FALSE);
+    $condition = $this->buildTableNameCondition($table_expression, 'LIKE');
 
     $condition->compile($this->connection, $this);
+
+    $prefix_length = strlen($this->connection->tablePrefix());
+    $tables = [];
     // Normally, we would heartily discourage the use of string
     // concatenation for conditionals like this however, we
     // couldn't use db_select() here because it would prefix
     // information_schema.tables and the query would fail.
     // Don't use {} around information_schema.tables table.
-    return $this->connection->query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0);
+    foreach ($this->connection->query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments()) as $table) {
+      // Remove the prefix from the returned tables.
+      $unprefixed_table_name = substr($table->table_name, $prefix_length);
+      // The pattern can match a table which is the same as the prefix. That
+      // will become an empty string when we remove the prefix, which will
+      // probably surprise the caller, besides not being a prefixed table. So
+      // remove it.
+      if (!empty($unprefixed_table_name)) {
+        $tables[$unprefixed_table_name] = $unprefixed_table_name;
+      }
+    }
+    return $tables;
   }
 
   /**
diff --git a/core/modules/simpletest/src/BrowserTestBase.php b/core/modules/simpletest/src/BrowserTestBase.php
index cd77a98..7d6b4b4 100644
--- a/core/modules/simpletest/src/BrowserTestBase.php
+++ b/core/modules/simpletest/src/BrowserTestBase.php
@@ -324,10 +324,9 @@ protected function cleanupEnvironment() {
     $test_connection_info = Database::getConnectionInfo('default');
     $test_prefix = $test_connection_info['default']['prefix']['default'];
     if ($original_prefix != $test_prefix) {
-      $tables = Database::getConnection()->schema()->findTables($test_prefix . '%');
-      $prefix_length = strlen($test_prefix);
+      $tables = Database::getConnection()->schema()->findTables('%');
       foreach ($tables as $table) {
-        if (Database::getConnection()->schema()->dropTable(substr($table, $prefix_length))) {
+        if (Database::getConnection()->schema()->dropTable($table)) {
           unset($tables[$table]);
         }
       }
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 4104b4b..ca7d474 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -1286,10 +1286,9 @@ private function restoreEnvironment() {
     $test_connection_info = Database::getConnectionInfo('default');
     $test_prefix = $test_connection_info['default']['prefix']['default'];
     if ($original_prefix != $test_prefix) {
-      $tables = Database::getConnection()->schema()->findTables($test_prefix . '%');
-      $prefix_length = strlen($test_prefix);
+      $tables = Database::getConnection()->schema()->findTables('%');
       foreach ($tables as $table) {
-        if (Database::getConnection()->schema()->dropTable(substr($table, $prefix_length))) {
+        if (Database::getConnection()->schema()->dropTable($table)) {
           unset($tables[$table]);
         }
       }
diff --git a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
index b22ece7..4c8343f 100644
--- a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
+++ b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\simpletest\Tests;
 
+use Drupal\Core\Database\Database;
 use Drupal\simpletest\KernelTestBase;
 
 /**
@@ -324,4 +325,39 @@ public function testDrupalGetProfile() {
     $this->assertNull(drupal_get_profile());
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function run(array $methods = array()) {
+    parent::run($methods);
+
+    // Check that all tables of the test instance have been deleted. At this
+    // point the original database connection is restored so we need to prefix
+    // the tables.
+    $connection = Database::getConnection();
+    if ($connection->databaseType() != 'sqlite') {
+      $tables = $connection->schema()->findTables($this->databasePrefix . '%');
+      $this->assertTrue(empty($tables), 'All test tables have been removed.');
+    }
+    else {
+      // We don't have the test instance connection anymore so we have to
+      // re-attach its database and then use the same query as
+      // \Drupal\Core\Database\Driver\sqlite\Schema::findTables().
+      // @see \Drupal\Core\Database\Driver\sqlite\Connection::__construct()
+      $info = Database::getConnectionInfo();
+      $connection->query('ATTACH DATABASE :database AS :prefix', [
+        ':database' => $info['default']['database'] . '-' . $this->databasePrefix,
+        ':prefix' => $this->databasePrefix
+      ]);
+
+      $result = $connection->query("SELECT name FROM " . $this->databasePrefix . ".sqlite_master WHERE type = :type AND name LIKE :table_name AND name NOT LIKE :pattern", array(
+        ':type' => 'table',
+        ':table_name' => '%',
+        ':pattern' => 'sqlite_%',
+      ))->fetchAllKeyed(0, 0);
+
+      $this->assertTrue(empty($result), 'All test tables have been removed.');
+    }
+  }
+
 }
