diff --git a/composer.json b/composer.json
index 646fd94203..9f16348bd6 100644
--- a/composer.json
+++ b/composer.json
@@ -52,7 +52,7 @@
         "post-autoload-dump": "Drupal\\Core\\Composer\\Composer::ensureHtaccess",
         "post-package-install": "Drupal\\Core\\Composer\\Composer::vendorTestCodeCleanup",
         "post-package-update": "Drupal\\Core\\Composer\\Composer::vendorTestCodeCleanup",
-        "post-install-cmd": "Drupal\\Core\\Composer\\Composer::upgradePHPUnit",
+        "drupal-phpunit-upgrade-check": "Drupal\\Core\\Composer\\Composer::upgradePHPUnit",
         "drupal-phpunit-upgrade": "@composer update phpunit/phpunit --with-dependencies --no-progress",
         "phpcs": "phpcs --standard=core/phpcs.xml.dist --runtime-set installed_paths $($COMPOSER_BINARY config vendor-dir)/drupal/coder/coder_sniffer --",
         "phpcbf": "phpcbf --standard=core/phpcs.xml.dist --runtime-set installed_paths $($COMPOSER_BINARY config vendor-dir)/drupal/coder/coder_sniffer --"
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index ae33bb5410..966db3aad0 100644
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -18,10 +18,9 @@
 use Drupal\simpletest\TestBase;
 use Drupal\simpletest\TestDiscovery;
 use PHPUnit\Framework\TestCase;
+use PHPUnit\Runner\Version;
 use Symfony\Component\HttpFoundation\Request;
 
-$autoloader = require_once __DIR__ . '/../../autoload.php';
-
 // Define some colors for display.
 // A nice calming green.
 const SIMPLETEST_SCRIPT_COLOR_PASS = 32;
@@ -37,11 +36,6 @@
 const SIMPLETEST_SCRIPT_EXIT_FAILURE = 1;
 const SIMPLETEST_SCRIPT_EXIT_EXCEPTION = 2;
 
-if (!class_exists(TestCase::class)) {
-  echo "\nrun-tests.sh requires the PHPUnit testing framework. Please use 'composer install --dev' to ensure that it is present.\n\n";
-  exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
-}
-
 // Set defaults and get overrides.
 list($args, $count) = simpletest_script_parse_args();
 
@@ -52,14 +46,9 @@
 
 simpletest_script_init();
 
-try {
-  $request = Request::createFromGlobals();
-  $kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
-  $kernel->prepareLegacyRequest($request);
-}
-catch (Exception $e) {
-  echo (string) $e;
-  exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
+if (!class_exists(TestCase::class)) {
+  echo "\nrun-tests.sh requires the PHPUnit testing framework. Please use 'composer install --dev' to ensure that it is present.\n\n";
+  exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
 }
 
 if ($args['execute-test']) {
@@ -141,6 +130,18 @@
   exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
 }
 
+// Ensure we have the correct PHPUnit version for the version of PHP.
+if (class_exists('\PHPUnit_Runner_Version')) {
+  $phpunit_version = \PHPUnit_Runner_Version::id();
+}
+else {
+  $phpunit_version = Version::id();
+}
+if (version_compare(PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, '7.2') >= 0 && version_compare($phpunit_version, '6.1') < 0) {
+  simpletest_script_print_error("PHPUnit testing framework version 6 or greater is required when running on PHP 7.2 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.");
+  exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
+}
+
 $test_list = simpletest_script_get_test_list();
 
 // Try to allocate unlimited time to run the tests.
@@ -462,6 +463,31 @@ function simpletest_script_init() {
     exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
   }
 
+  // Detect if we're in the top-level process using the private 'execute-test'
+  // argument.
+  if (!$args['execute-test']) {
+    // Determine if the current user is likely to be able to run composer to
+    // update PHPUnit if necessary. There is no direct way in PHP of determining
+    // the user running the process, therefore create a file and check if the
+    // owner is the same as the owner of the current script. The important thing
+    // is to allow drupal.org's testing infrastructure to update PHPUnit
+    // automatically. In all other cases it is okay to emit the error message
+    // telling the user to do the upgrade themselves.
+    $tmp = tempnam(sys_get_temp_dir(), 'drupal');
+    if (fileowner($tmp) === getmyuid() && getmyuid() !== FALSE) {
+      // Update PHPUnit if needed and possible. There is a later check once the
+      // autoloader is in place to ensure we're on the correct version. We need to
+      // do this before the autoloader is in place to ensure that it is correct.
+      $composer = ($composer = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar`))
+        ? $php . ' ' . escapeshellarg($composer)
+        : 'composer';
+      passthru("$composer run-script drupal-phpunit-upgrade-check");
+    }
+    unlink($tmp);
+  }
+
+  $autoloader = require_once __DIR__ . '/../../autoload.php';
+
   // Get URL from arguments.
   if (!empty($args['url'])) {
     $parsed_url = parse_url($args['url']);
@@ -520,6 +546,17 @@ function simpletest_script_init() {
   }
 
   chdir(realpath(__DIR__ . '/../..'));
+
+  // Prepare the kernel.
+  try {
+    $request = Request::createFromGlobals();
+    $kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
+    $kernel->prepareLegacyRequest($request);
+  }
+  catch (Exception $e) {
+    echo (string) $e;
+    exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
+  }
 }
 
 /**
diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index 50fef61ee6..429514179f 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -150,6 +150,19 @@ function drupal_phpunit_populate_class_loader() {
 // Do class loader population.
 drupal_phpunit_populate_class_loader();
 
+// Ensure we have the correct PHPUnit version for the version of PHP.
+if (class_exists('\PHPUnit_Runner_Version')) {
+  $phpunit_version = \PHPUnit_Runner_Version::id();
+}
+else {
+  $phpunit_version = Version::id();
+}
+if (version_compare(PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, '7.2') >= 0 && version_compare($phpunit_version, '6.1') < 0) {
+  $message = "PHPUnit testing framework version 6 or greater is required when running on PHP 7.2 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.";
+  echo "\033[31m" . $message . "\n\033[0m";
+  exit(1);
+}
+
 // Set sane locale settings, to ensure consistent string, dates, times and
 // numbers handling.
 // @see \Drupal\Core\DrupalKernel::bootEnvironment()
@@ -170,7 +183,7 @@ function drupal_phpunit_populate_class_loader() {
 
 // PHPUnit 4 to PHPUnit 6 bridge. Tests written for PHPUnit 4 need to work on
 // PHPUnit 6 with a minimum of fuss.
-if (class_exists('PHPUnit\Runner\Version') && version_compare(Version::id(), '6.1', '>=')) {
+if (version_compare($phpunit_version, '6.1', '>=')) {
   class_alias('\PHPUnit\Framework\AssertionFailedError', '\PHPUnit_Framework_AssertionFailedError');
   class_alias('\PHPUnit\Framework\Constraint\Count', '\PHPUnit_Framework_Constraint_Count');
   class_alias('\PHPUnit\Framework\Error\Error', '\PHPUnit_Framework_Error');
