diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 5594dd5..3e3ae6b 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -79,8 +79,12 @@
 simpletest_script_reporter_init();
 
 // Execute tests.
+$had_fails = FALSE;
 for ($i = 0; $i < $args['repeat']; $i++) {
-  simpletest_script_execute_batch($test_list);
+  $had_fail_or_exception = simpletest_script_execute_batch($test_list);
+  if (!$had_fail_or_exception) {
+    $had_fails = TRUE;
+  }
 }
 
 // Stop the timer.
@@ -99,7 +103,12 @@
 }
 
 // Test complete, exit.
-exit;
+if ($had_fails) {
+  exit(1);
+}
+else {
+  exit(0);
+}
 
 /**
  * Print help text.
@@ -405,6 +414,9 @@ function simpletest_script_execute_batch($test_classes) {
     // Wait for children every 200ms.
     usleep(200000);
 
+    // Keep track of whether we had any failures or exceptions.
+    $had_fail = FALSE;
+
     // Check if some children finished.
     foreach ($children as $cid => $child) {
       $status = proc_get_status($child['process']);
@@ -413,6 +425,7 @@ function simpletest_script_execute_batch($test_classes) {
         proc_close($child['process']);
         if ($status['exitcode']) {
           echo 'FATAL ' . $child['class'] . ': test runner returned a non-zero error code (' . $status['exitcode'] . ').' . "\n";
+          $had_fail = TRUE;
           if ($args['die-on-fail']) {
             list($db_prefix, ) = simpletest_last_test_get($child['test_id']);
             $test_directory = 'sites/simpletest/' . substr($db_prefix, 10);
@@ -431,6 +444,7 @@ function simpletest_script_execute_batch($test_classes) {
         unset($children[$cid]);
       }
     }
+    return $had_fail;
   }
 }
 
@@ -506,7 +520,12 @@ function simpletest_script_run_one_test($test_id, $test_class) {
     simpletest_script_print($info['name'] . ' ' . _simpletest_format_summary_line($test->results) . "\n", simpletest_script_color_code($status));
 
     // Finished, kill this runner.
-    exit(0);
+    if ($had_fails || $had_exceptions) {
+      exit(1);
+    }
+    else {
+      exit(0);
+    }
   }
   // DrupalTestCase::run() catches exceptions already, so this is only reached
   // when an exception is thrown in the wrapping test runner environment.
