diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index 38d57e317f..8847857fb5 100644
--- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -510,6 +510,7 @@ protected function installParameters() {
     unset($connection_info['default']['autoload']);
     unset($connection_info['default']['pdo']);
     unset($connection_info['default']['init_commands']);
+    unset($connection_info['default']['isolation_level']);
     // Remove database connection info that is not used by SQLite.
     if ($driver === 'sqlite') {
       unset($connection_info['default']['username']);
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 df5f4230ed..241fb99b41 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
@@ -301,6 +301,8 @@ protected function getCredentials() {
     $drivers = drupal_get_database_types();
     $form = $drivers[$driver]->getFormOptions($connection_options);
     $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
+    // Remove isolation_level since that options is not configurable in the UI.
+    unset($connection_options['isolation_level']);
     $edit = [
       $driver => $connection_options,
       'source_private_file_path' => $this->getSourceBasePath(),
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/FilePathTest.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/FilePathTest.php
index 6ccb1f97ff..59487a7488 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/FilePathTest.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/FilePathTest.php
@@ -127,6 +127,8 @@ public function testFilePath(string $file_private_path, string $file_public_path
     $drivers = drupal_get_database_types();
     $form = $drivers[$driver]->getFormOptions($connection_options);
     $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
+    // Remove isolation_level since that options is not configurable in the UI.
+    unset($connection_options['isolation_level']);
     $edit = [
       $driver => $connection_options,
       'version' => '7',
diff --git a/core/modules/mysql/mysql.install b/core/modules/mysql/mysql.install
index 42ed7344af..6633a0ed50 100644
--- a/core/modules/mysql/mysql.install
+++ b/core/modules/mysql/mysql.install
@@ -31,13 +31,44 @@ function mysql_requirements($phase) {
         $query = 'SELECT @@SESSION.transaction_isolation';
       }
 
+      $tables_missing_key = [];
+      $missing_primary_key = FALSE;
+      $tables = $connection->schema()->findTables('%');
       $isolation_level = $connection->query($query)->fetchField();
+      $severity_level = REQUIREMENT_INFO;
+      $description = 'This site is using the database transaction level "READ COMMITTED".';
+
+      foreach ($tables as $table) {
+        $primary_key_column = Database::getConnection()->query("SHOW KEYS FROM {" . $table . "} WHERE Key_name = 'PRIMARY'")->fetchAllAssoc('Column_name');
+        if (empty($primary_key_column)) {
+          $missing_primary_key = TRUE;
+          $tables_missing_key[] = $table;
+        }
+      }
+
+      $tables_missing_key_text = 'For this to work properly all tables should have a primary key. The following table(s) do no have a primary key: '. implode(', ', $tables_missing_key);
+
+      if ($isolation_level == 'READ-COMMITTED' && $missing_primary_key) {
+        $severity_level = REQUIREMENT_ERROR;
+        $description = 'This site is using the database transaction level "READ COMMITTED". '. $tables_missing_key_text;
+      }
+      elseif ($isolation_level == 'REPEATABLE-READ') {
+        $severity_level = REQUIREMENT_WARNING;
+        $description = 'This site is using the database transaction level "REPEATABLE READ". The recommended database transaction level for Drupal is "READ COMMITTED".';
+        if ($missing_primary_key) {
+          $description .= ' ' . $tables_missing_key_text;
+        }
+      }
+      elseif ($isolation_level == 'READ-UNCOMMITTED' || $isolation_level == 'SERIALIZED') {
+        $severity_level = REQUIREMENT_ERROR;
+        $description = 'This site is using the database transaction level "'.$isolation_level. '". This database transaction level is not supported by Drupal. The recommended database transaction level for Drupal is "READ COMMITTED".';
+      }
 
       $requirements['mysql_transaction_level'] = [
         'title' => t('Database Isolation Level'),
-        'severity' => $isolation_level === 'READ-COMMITTED' ? REQUIREMENT_OK : REQUIREMENT_WARNING,
+        'severity' => $severity_level,
         'value' => $isolation_level,
-        'description' => t('For the best performance and to minimize locking issues, the READ-COMMITTED transaction isolation level is recommended. See the <a href=":performance_doc">setting MySQL transaction isolation level</a> page for more information.', [
+        'description' => t($description. ' See the <a href=":performance_doc">setting MySQL transaction isolation level</a> page for more information.', [
           ':performance_doc' => 'https://www.drupal.org/docs/system-requirements/setting-the-mysql-transaction-isolation-level',
         ]),
       ];
diff --git a/core/modules/mysql/src/Driver/Database/mysql/Connection.php b/core/modules/mysql/src/Driver/Database/mysql/Connection.php
index 7c9fab2836..d128f3e22a 100644
--- a/core/modules/mysql/src/Driver/Database/mysql/Connection.php
+++ b/core/modules/mysql/src/Driver/Database/mysql/Connection.php
@@ -203,6 +203,15 @@ public static function open(array &$connection_options = []) {
     $connection_options['init_commands'] += [
       'sql_mode' => "SET sql_mode = 'ANSI,TRADITIONAL'",
     ];
+    // Only set the transaction isolation level when the connection option has
+    // been set to 'READ COMMITTED' or 'REPEATABLE READ'.
+    if (!empty($connection_options['isolation_level']) &&
+      in_array($connection_options['isolation_level'],
+        ['READ COMMITTED', 'REPEATABLE READ'], TRUE)) {
+      $connection_options['init_commands'] += [
+        'isolation_level' => 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $connection_options['isolation_level'],
+      ];
+    }
 
     // Execute initial commands.
     foreach ($connection_options['init_commands'] as $sql) {
diff --git a/core/modules/mysql/src/Driver/Database/mysql/Install/Tasks.php b/core/modules/mysql/src/Driver/Database/mysql/Install/Tasks.php
index 3a41083d68..3fbd49c7b7 100644
--- a/core/modules/mysql/src/Driver/Database/mysql/Install/Tasks.php
+++ b/core/modules/mysql/src/Driver/Database/mysql/Install/Tasks.php
@@ -174,6 +174,19 @@ public function getFormOptions(array $database) {
     if (empty($form['advanced_options']['port']['#default_value'])) {
       $form['advanced_options']['port']['#default_value'] = '3306';
     }
+    $form['advanced_options']['isolation_level'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Transaction isolation level'),
+      '#options' => [
+        'READ COMMITTED' => $this->t('Read Committed'),
+        'REPEATABLE READ' => $this->t('Repeatable Read'),
+        'DO NOT SET BY DRUPAL' => $this->t('Do not set by Drupal'),
+      ],
+      '#default_value' => $database['isolation_level'] ?? 'READ COMMITTED',
+      '#description' => $this->t('The recommended database transaction level for Drupal is "READ COMMITTED". By selecting the option "READ COMMITTED" Drupal will set the transaction level on every page request. If possible, we recommend to set database transaction level globally. In that case select the option "DO NOT SET BY DRUPAL". For more information, see the <a href=":performance_doc">setting MySQL transaction isolation level</a> page.', [
+        ':performance_doc' => 'https://www.drupal.org/docs/system-requirements/setting-the-mysql-transaction-isolation-level',
+      ]),
+    ];
 
     return $form;
   }
diff --git a/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelExistingSettingsTest.php b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelExistingSettingsTest.php
new file mode 100644
index 0000000000..ace161dc5b
--- /dev/null
+++ b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelExistingSettingsTest.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Drupal\Tests\mysql\Functional;
+
+use Drupal\Core\Database\Database;
+use Drupal\FunctionalTests\Installer\InstallerExistingSettingsTest;
+
+/**
+ * Tests the isolation_level setting with existing database settings.
+ *
+ * @group Installer
+ */
+class InstallerIsolationLevelExistingSettingsTest extends InstallerExistingSettingsTest {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function prepareEnvironment() {
+    parent::prepareEnvironment();
+
+    $connection_info = Database::getConnectionInfo();
+    // The isolation_level option is only available for MySQL.
+    if ($connection_info['default']['driver'] !== 'mysql') {
+      $this->markTestSkipped("This test does not support the {$connection_info['default']['driver']} database driver.");
+    }
+  }
+
+  /**
+   * Verifies that isolation_level is not set in the database settings.
+   */
+  public function testInstaller() {
+    $contents = file_get_contents($this->container->getParameter('app.root') . '/' . $this->siteDirectory . '/settings.php');
+
+    // Test that isolation_level was not set.
+    $this->assertStringNotContainsString("'isolation_level' => 'READ COMMITTED'", $contents);
+    $this->assertStringNotContainsString("'isolation_level' => 'REPEATABLE READ'", $contents);
+
+    // Change the default database connection to use the isolation level from
+    // the test.
+    $connection_info = Database::getConnectionInfo();
+    $driver_test_connection = $connection_info['default'];
+    // We have asserted that the isolation level was not set.
+    unset($driver_test_connection['isolation_level']);
+    unset($driver_test_connection['init_commands']);
+
+    Database::renameConnection('default', 'original_database_connection');
+    Database::addConnectionInfo('default', 'default', $driver_test_connection);
+    // Close and reopen the database connection, so the database init commands
+    // get executed.
+    Database::closeConnection('default', 'default');
+    $connection = Database::getConnection('default', 'default');
+
+    $query = 'SELECT @@SESSION.tx_isolation';
+    // The database variable "tx_isolation" has been removed in MySQL v8.0 and
+    // has been replaced by "transaction_isolation".
+    // @see https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_tx_isolation
+    if (!$connection->isMariaDb() && version_compare($connection->version(), '8.0.0-AnyName', '>')) {
+      $query = 'SELECT @@SESSION.transaction_isolation';
+    }
+
+    // Test that transaction level is REPEATABLE READ.
+    $this->assertEquals('REPEATABLE-READ', $connection->query($query)->fetchField());
+
+    // Restore the old database connection.
+    Database::addConnectionInfo('default', 'default', $connection_info['default']);
+    Database::closeConnection('default', 'default');
+    Database::getConnection('default', 'default');
+  }
+
+}
diff --git a/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelNoDatabaseSettingsTest.php b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelNoDatabaseSettingsTest.php
new file mode 100644
index 0000000000..f54dca0595
--- /dev/null
+++ b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelNoDatabaseSettingsTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\Tests\mysql\Functional;
+
+use Drupal\Core\Database\Database;
+use Drupal\FunctionalTests\Installer\InstallerTestBase;
+
+/**
+ * Tests the isolation_level setting with no database settings.
+ *
+ * @group Installer
+ */
+class InstallerIsolationLevelNoDatabaseSettingsTest extends InstallerTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function prepareEnvironment() {
+    parent::prepareEnvironment();
+
+    // The isolation_level option is only available for MySQL.
+    $connection_info = Database::getConnectionInfo();
+    if ($connection_info['default']['driver'] !== 'mysql') {
+      $this->markTestSkipped("This test does not support the {$connection_info['default']['driver']} database driver.");
+    }
+  }
+
+  /**
+   * Verifies that the isolation_level was added to the database settings.
+   */
+  public function testInstaller() {
+    $contents = file_get_contents($this->container->getParameter('app.root') . '/' . $this->siteDirectory . '/settings.php');
+
+    // Test that isolation_level was set to "READ COMMITTED".
+    $this->assertStringContainsString("'isolation_level' => 'READ COMMITTED',", $contents);
+
+    // Change the default database connection to use the isolation level from
+    // the test.
+    $connection_info = Database::getConnectionInfo();
+    $driver_test_connection = $connection_info['default'];
+    // We have asserted that the isolation level was set to 'READ COMMITTED'.
+    $driver_test_connection['isolation_level'] = 'READ COMMITTED';
+    unset($driver_test_connection['init_commands']);
+
+    Database::renameConnection('default', 'original_database_connection');
+    Database::addConnectionInfo('default', 'default', $driver_test_connection);
+    // Close and reopen the database connection, so the database init commands
+    // get executed.
+    Database::closeConnection('default', 'default');
+    $connection = Database::getConnection('default', 'default');
+
+    $query = 'SELECT @@SESSION.tx_isolation';
+    // The database variable "tx_isolation" has been removed in MySQL v8.0 and
+    // has been replaced by "transaction_isolation".
+    // @see https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_tx_isolation
+    if (!$connection->isMariaDb() && version_compare($connection->version(), '8.0.0-AnyName', '>')) {
+      $query = 'SELECT @@SESSION.transaction_isolation';
+    }
+
+    // Test that transaction level is READ-COMMITTED.
+    $this->assertEquals('READ-COMMITTED', $connection->query($query)->fetchField());
+
+    // Restore the old database connection.
+    Database::addConnectionInfo('default', 'default', $connection_info['default']);
+    Database::closeConnection('default', 'default');
+    Database::getConnection('default', 'default');
+  }
+
+}
diff --git a/core/modules/mysql/tests/src/Functional/RequirementsTest.php b/core/modules/mysql/tests/src/Functional/RequirementsTest.php
index d7ba5f18dc..6c3804f04a 100644
--- a/core/modules/mysql/tests/src/Functional/RequirementsTest.php
+++ b/core/modules/mysql/tests/src/Functional/RequirementsTest.php
@@ -44,6 +44,7 @@ public function testIsolationLevelWarningNotDisplaying() {
       'access site reports',
     ]);
     $this->drupalLogin($admin_user);
+    $connection = Database::getConnection();
 
     // Set the isolation level to a level that produces a warning.
     $this->writeIsolationLevelSettings('REPEATABLE READ');
@@ -51,12 +52,12 @@ public function testIsolationLevelWarningNotDisplaying() {
     // Check the message is not a warning.
     $this->drupalGet('admin/reports/status');
     $elements = $this->xpath('//details[@class="system-status-report__entry"]//div[contains(text(), :text)]', [
-      ':text' => 'For the best performance and to minimize locking issues, the READ-COMMITTED',
+      ':text' => 'This site is using the database transaction level "REPEATABLE READ". The recommended database',
     ]);
     $this->assertCount(1, $elements);
     $this->assertStringStartsWith('REPEATABLE-READ', $elements[0]->getParent()->getText());
     // Ensure it is a warning.
-    $this->assertStringContainsString('warning', $elements[0]->getParent()->getParent()->find('css', 'summary')->getAttribute('class'));
+    $this->assertStringContainsString('warning', $elements[0]->getParent()->getParent()->find('css', 'summary')->getAttribute('class'));    // Set the isolation level to a level that produces a warning.
 
     // Rollback the isolation level to read committed.
     $this->writeIsolationLevelSettings('READ COMMITTED');
@@ -64,12 +65,49 @@ public function testIsolationLevelWarningNotDisplaying() {
     // Check the message is not a warning.
     $this->drupalGet('admin/reports/status');
     $elements = $this->xpath('//details[@class="system-status-report__entry"]//div[contains(text(), :text)]', [
-      ':text' => 'For the best performance and to minimize locking issues, the READ-COMMITTED',
+      ':text' => 'This site is using the database transaction level "READ COMMITTED"',
     ]);
     $this->assertCount(1, $elements);
     $this->assertStringStartsWith('READ-COMMITTED', $elements[0]->getParent()->getText());
     // Ensure it is a not a warning.
     $this->assertStringNotContainsString('warning', $elements[0]->getParent()->getParent()->find('css', 'summary')->getAttribute('class'));
+
+    $specification = [
+      'fields' => [
+        'text' => [
+          'type' => 'text',
+          'description' => 'A text field',
+        ],
+      ],
+    ];
+
+    $connection->schema()->createTable('test_table_without_primary_key', $specification);
+
+    // Set the isolation level to a level that produces a warning.
+    $this->writeIsolationLevelSettings('REPEATABLE READ');
+
+    // Check the message is not a warning.
+    $this->drupalGet('admin/reports/status');
+    $elements = $this->xpath('//details[@class="system-status-report__entry"]//div[contains(text(), :text)]', [
+      ':text' => 'This site is using the database transaction level "REPEATABLE READ". The recommended database transaction level for Drupal is "READ COMMITTED". For this to work properly all tables should have a primary key. The following table(s) do no have a primary key:',
+    ]);
+    $this->assertCount(1, $elements);
+    $this->assertStringStartsWith('REPEATABLE-READ', $elements[0]->getParent()->getText());
+    // Ensure it is a warning.
+    $this->assertStringContainsString('warning', $elements[0]->getParent()->getParent()->find('css', 'summary')->getAttribute('class'));    // Set the isolation level to a level that produces a warning.
+
+    // Rollback the isolation level to read committed.
+    $this->writeIsolationLevelSettings('READ COMMITTED');
+
+    // Check the message is not a warning.
+    $this->drupalGet('admin/reports/status');
+    $elements = $this->xpath('//details[@class="system-status-report__entry"]//div[contains(text(), :text)]', [
+      ':text' => 'This site is using the database transaction level "READ COMMITTED". For this to work properly all tables should have a primary key. The following table(s) do no have a primary key:',
+    ]);
+    $this->assertCount(1, $elements);
+    $this->assertStringStartsWith('READ-COMMITTED', $elements[0]->getParent()->getText());
+    // Ensure it is a not a warning.
+    $this->assertStringContainsString('error', $elements[0]->getParent()->getParent()->find('css', 'summary')->getAttribute('class'));
   }
 
   /**
@@ -81,7 +119,7 @@ public function testIsolationLevelWarningNotDisplaying() {
   private function writeIsolationLevelSettings(string $isolation_level) {
     $settings['databases']['default']['default']['init_commands'] = (object) [
       'value'    => [
-        'isolation' => "SET SESSION TRANSACTION ISOLATION LEVEL {$isolation_level}",
+        'isolation_level' => "SET SESSION TRANSACTION ISOLATION LEVEL {$isolation_level}",
       ],
       'required' => TRUE,
     ];
diff --git a/core/modules/mysql/tests/src/Functional/mysql/PrimaryKeyExistsTest.php b/core/modules/mysql/tests/src/Functional/mysql/PrimaryKeyExistsTest.php
new file mode 100644
index 0000000000..bc02cb80d8
--- /dev/null
+++ b/core/modules/mysql/tests/src/Functional/mysql/PrimaryKeyExistsTest.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\Tests\mysql\Functional\mysql;
+
+use Drupal\Core\Database\Database;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests isolation level warning when the config is set in settings.php.
+ *
+ * @group mysql
+ */
+class PrimaryKeyExistsTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['mysql'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * Test the isolation level warning message on status page.
+   */
+  public function testAllTablesOnPrimaryKey() {
+    $connection = Database::getConnection();
+
+    $admin_user = $this->drupalCreateUser([
+      'administer site configuration',
+      'access site reports',
+    ]);
+    $this->drupalLogin($admin_user);
+
+    // Check the message is not a warning.
+    $this->drupalGet('admin/reports/status');
+    $elements = $this->xpath('//details[@class="system-status-report__entry"]//div[contains(text(), :text)]', [
+      ':text' => 'To insure correct operation with READ-COMMITTED, ensure all tables have a primary key.',
+    ]);
+    $this->assertCount(1, $elements);
+    $this->assertStringNotContainsString('warning', $elements[0]->getParent()->getParent()->find('css', 'summary')->getAttribute('class'));
+
+    $connection->schema()->createTable('test_primary_key', [
+      'fields' => [
+        'id' => [
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ],
+      ],
+    ]);
+
+    $this->assertTrue($connection->schema()->tableExists('test_primary_key'));
+
+    // Check the message is not a warning.
+    $this->drupalGet('admin/reports/status');
+    $elements = $this->xpath('//details[@class="system-status-report__entry"]//div[contains(text(), :text)]', [
+      ':text' => 'To insure correct operation with READ-COMMITTED, ensure all tables have a primary key. The following table(s) do not contain a primary key: test_primary_key',
+    ]);
+    $this->assertCount(1, $elements);
+    // Ensure it is a warning.
+    $this->assertStringContainsString('warning', $elements[0]->getParent()->getParent()->find('css', 'summary')->getAttribute('class'));
+
+  }
+
+}
diff --git a/core/phpstan-baseline.neon b/core/phpstan-baseline.neon
index 4b0b775af4..5fa10c3be9 100644
--- a/core/phpstan-baseline.neon
+++ b/core/phpstan-baseline.neon
@@ -2955,11 +2955,6 @@ parameters:
 			count: 12
 			path: tests/Drupal/KernelTests/Core/Cache/GenericCacheBackendUnitTestBase.php
 
-		-
-			message: "#^Variable \\$expected_driver might not be defined\\.$#"
-			count: 2
-			path: tests/Drupal/KernelTests/Core/Database/DriverSpecificKernelTestBase.php
-
 		-
 			message: "#^Relying on entity queries to check access by default is deprecated in drupal\\:9\\.2\\.0 and an error will be thrown from drupal\\:10\\.0\\.0\\. Call \\\\Drupal\\\\Core\\\\Entity\\\\Query\\\\QueryInterface\\:\\:accessCheck\\(\\) with TRUE or FALSE to specify whether access should be checked\\.$#"
 			count: 75
diff --git a/core/tests/Drupal/FunctionalTests/Core/Database/DriverSpecificBrowserTestBase.php b/core/tests/Drupal/FunctionalTests/Core/Database/DriverSpecificBrowserTestBase.php
new file mode 100644
index 0000000000..f3c4b8868a
--- /dev/null
+++ b/core/tests/Drupal/FunctionalTests/Core/Database/DriverSpecificBrowserTestBase.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Drupal\FunctionalTests\Core\Database;
+
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\DriverSpecificTrait;
+
+// cSpell:ignore mymodule mydriver
+
+/**
+ * Base class for driver specific browser tests.
+ *
+ * Driver specific tests should be created in the
+ * \Drupal\Tests\mymodule\Functional\mydriver namespace,
+ * and their execution will only occur when the database
+ * driver of the SUT is provided by 'mymodule' and named 'mydriver'.
+ */
+abstract class DriverSpecificBrowserTestBase extends BrowserTestBase {
+  use DriverSpecificTrait;
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Database/DriverSpecificKernelTestBase.php b/core/tests/Drupal/KernelTests/Core/Database/DriverSpecificKernelTestBase.php
index 9be2cbe0a8..937dbee432 100644
--- a/core/tests/Drupal/KernelTests/Core/Database/DriverSpecificKernelTestBase.php
+++ b/core/tests/Drupal/KernelTests/Core/Database/DriverSpecificKernelTestBase.php
@@ -31,6 +31,7 @@ protected function setUp(): void {
     // is not the one the test requires, skip before test database
     // initialization so to save cycles.
     $this->root = static::getDrupalRoot();
+    $expected_driver = '';
     $connectionInfo = $this->getDatabaseConnectionInfo();
     $test_class_parts = explode('\\', get_class($this));
     $expected_provider = $test_class_parts[2] ?? '';
diff --git a/core/tests/Drupal/Tests/DriverSpecificTrait.php b/core/tests/Drupal/Tests/DriverSpecificTrait.php
new file mode 100644
index 0000000000..5486ea3054
--- /dev/null
+++ b/core/tests/Drupal/Tests/DriverSpecificTrait.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Drupal\Tests;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\Database;
+
+/**
+ * Provides a Traits Driver Specific.
+ */
+trait DriverSpecificTrait {
+
+  /**
+   * The database connection for testing.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected Connection $connection;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    // Find the current SUT database driver from the connection info. If that
+    // is not the one the test requires, skip before test database
+    // initialization so to save cycles.
+    $this->root = static::getDrupalRoot();
+    $expected_driver = '';
+
+    if (method_exists($this, 'getDatabaseConnectionInfo')) {
+      $connectionInfo = $this->getDatabaseConnectionInfo();
+    }
+    else {
+      $connectionInfo = Database::getConnectionInfo();
+    }    $test_class_parts = explode('\\', get_class($this));
+    $expected_provider = $test_class_parts[2] ?? '';
+    for ($i = 3; $i < count($test_class_parts); $i++) {
+      if (in_array($test_class_parts[$i], ['Kernel', 'Functional'], TRUE)) {
+        $expected_driver = $test_class_parts[$i + 1] ?? '';
+        break;
+      }
+    }
+    if ($connectionInfo['default']['driver'] !== $expected_driver) {
+      $this->markTestSkipped("This test only runs for the database driver '$expected_driver'. Current database driver is '{$connectionInfo['default']['driver']}'.");
+    }
+
+    parent::setUp();
+    $this->connection = Database::getConnection();
+
+    // After database initialization, the database driver may be not provided
+    // by the expected module; skip test in that case.
+    $running_provider = $this->connection->getProvider();
+    $running_driver = $this->connection->driver();
+    if ($running_provider !== $expected_provider || $running_driver !== $expected_driver) {
+      $this->markTestSkipped("This test only runs for the database driver '$expected_driver' provided by the '$expected_provider' module. Connected database driver is '$running_driver' provided by '$running_provider'.");
+    }
+  }
+
+}
