diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 70bdf4a..b91a784 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -16,6 +16,7 @@
 const SIMPLETEST_SCRIPT_COLOR_PASS = 32; // Green.
 const SIMPLETEST_SCRIPT_COLOR_FAIL = 31; // Red.
 const SIMPLETEST_SCRIPT_COLOR_EXCEPTION = 33; // Brown.
+const SIMPLETEST_SCRIPT_FAILS_OR_ERRORS = 2; // Status code for failed tests.
 
 // Set defaults and get overrides.
 list($args, $count) = simpletest_script_parse_args();
@@ -80,7 +81,7 @@
 }
 
 // Execute tests.
-simpletest_script_execute_batch($tests_to_run);
+$status = simpletest_script_execute_batch($tests_to_run);
 
 // Stop the timer.
 simpletest_script_reporter_timer_stop();
@@ -98,7 +99,7 @@
 }
 
 // Test complete, exit.
-exit;
+exit($status);
 
 /**
  * Print help text.
@@ -502,6 +503,9 @@ function simpletest_script_setup_database($new = FALSE) {
 function simpletest_script_execute_batch($test_classes) {
   global $args, $test_ids;
 
+  // Keeps track of failures or exceptions during the tests.
+  $has_fails_or_exceptions = FALSE;
+
   // Multi-process execution.
   $children = array();
   while (!empty($test_classes) || !empty($children)) {
@@ -518,7 +522,10 @@ function simpletest_script_execute_batch($test_classes) {
       // Process phpunit tests immediately since they are fast and we don't need
       // to fork for them.
       if (is_subclass_of($test_class, 'Drupal\Tests\UnitTestCase')) {
-        simpletest_script_run_phpunit($test_id, $test_class);
+        $exit_code = simpletest_script_run_phpunit($test_id, $test_class);
+        if ($exit_code) {
+          $has_fails_or_exceptions = TRUE;
+        }
         continue;
       }
 
@@ -550,6 +557,7 @@ function simpletest_script_execute_batch($test_classes) {
         // The child exited, unregister it.
         proc_close($child['process']);
         if ($status['exitcode']) {
+          $has_fails_or_exceptions = TRUE;
           echo 'FATAL ' . $child['class'] . ': test runner returned a non-zero error code (' . $status['exitcode'] . ').' . "\n";
           if ($args['die-on-fail']) {
             list($db_prefix, ) = simpletest_last_test_get($child['test_id']);
@@ -570,6 +578,9 @@ function simpletest_script_execute_batch($test_classes) {
       }
     }
   }
+  if ($has_fails_or_exceptions) {
+    return SIMPLETEST_SCRIPT_FAILS_OR_ERRORS;
+  }
 }
 
 /**
@@ -608,9 +619,15 @@ function simpletest_script_run_phpunit($test_id, $class) {
     }
   }
 
+  $exit_code = 0;
   foreach ($summaries as $class => $summary) {
     simpletest_script_reporter_display_summary($class, $summary);
+
+    if ($summary['#fail'] || $summary['#exception']) {
+      $exit_code = SIMPLETEST_SCRIPT_FAILS_OR_ERRORS;
+    }
   }
+  return($exit_code);
 }
 
 /**
@@ -627,8 +644,13 @@ function simpletest_script_run_one_test($test_id, $test_class) {
 
     simpletest_script_reporter_display_summary($test_class, $test->results);
 
+
     // Finished, kill this runner.
+    if ($test->results['#fail'] || $test->results['#exception']) {
+      exit(SIMPLETEST_SCRIPT_FAILS_OR_ERRORS);
+    }
     exit(0);
+
   }
   // DrupalTestCase::run() catches exceptions already, so this is only reached
   // when an exception is thrown in the wrapping test runner environment.
