diff --git a/core/modules/simpletest/tests/registry_test.class.inc b/core/modules/simpletest/tests/registry_test.class.inc
new file mode 100644
index 0000000..76cd322
--- /dev/null
+++ b/core/modules/simpletest/tests/registry_test.class.inc
@@ -0,0 +1,4 @@
+<?php
+
+class RegistryTestClass {}
+
diff --git a/core/modules/simpletest/tests/registry_test.info b/core/modules/simpletest/tests/registry_test.info
new file mode 100644
index 0000000..a4e68a7
--- /dev/null
+++ b/core/modules/simpletest/tests/registry_test.info
@@ -0,0 +1,7 @@
+name = Registry test
+description = Support module for registry testing.
+package = Testing
+version = VERSION
+core = 8.x
+hidden = TRUE
+files[] = registry_test.class.inc
diff --git a/core/modules/simpletest/tests/registry_test.module b/core/modules/simpletest/tests/registry_test.module
new file mode 100644
index 0000000..9c2e87e
--- /dev/null
+++ b/core/modules/simpletest/tests/registry_test.module
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * Implements hook_registry_files_alter().
+ */
+function registry_test_registry_files_alter(&$files, $modules) {
+  if (variable_get('registry_test_break_the_registry', FALSE)) {
+    unset($files[drupal_get_path('module', 'registry_test') . '/registry_test.class.inc']);
+  }
+}
+
+/**
+ * Implements hook_init().
+ */
+function registry_test_init() {
+  $oh_hai_thar = new RegistryTestClass();
+}
+
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 9da67ac..6786233 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -5101,6 +5101,10 @@ function _drupal_bootstrap_full() {
     drupal_theme_initialize();
     module_invoke_all('init');
   }
+  if (variable_get('registry_rebuild') && !defined('MAINTENANCE_MODE')) {
+    registry_rebuild();
+    variable_del('registry_rebuild');
+  }
 }
 
 /**
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 289d27a..6b58c83 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -19,6 +19,61 @@
 const REQUIRED_D7_SCHEMA_VERSION = '7069';
 
 /**
+ * Rebuilds the registry without a full bootstrap.
+ *
+ * This function rebuilds the registry without a full bootstrap, and without
+ * invoking hook_boot() or hook_init(). This can be useful when the registry
+ * holds incorrect or incomplete information, which prevents Drupal from
+ * being able to bootstrap fully.
+ */
+function update_rebuild_registry() {
+  require_once DRUPAL_ROOT . '/core/includes/common.inc';
+  require_once DRUPAL_ROOT . '/core/includes/registry.inc';
+
+  $connection_info = Database::getConnectionInfo();
+  $driver = $connection_info['default']['driver'];
+  require_once DRUPAL_ROOT . '/core/includes/database/query.inc';
+  require_once DRUPAL_ROOT . '/core/includes/database/select.inc';
+  require_once DRUPAL_ROOT . '/core/includes/database/' . $driver . '/query.inc';
+
+  // Get current list of modules and their files.
+  $modules = db_query("SELECT * FROM {system} WHERE type = 'module' AND status = 1")->fetchAll();
+  // Get the list of files we are going to parse.
+  $files = array();
+  foreach ($modules as $module) {
+    $dir = dirname($module->filename);
+
+    // Store the module directory for use in hook_registry_files_alter().
+    $module->dir = $dir;
+    $module->info = drupal_parse_info_file($module->dir . '/' . $module->name . '.info');
+    if (isset($module->info['files'])) {
+      // Add files for enabled modules to the registry.
+      foreach ($module->info['files'] as $file) {
+        $files["$dir/$file"] = array('module' => $module->name, 'weight' => $module->weight);
+      }
+    }
+  }
+  foreach (new RecursiveDirectoryIterator(DRUPAL_ROOT . '/core/includes') as $file) {
+    $filename = $file->getPathname();
+    if (substr($filename, -4) == '.inc') {
+      $files[$filename] = array('module' => '', 'weight' => 0);
+    }
+  }
+
+  $transaction = db_transaction();
+  try {
+    db_truncate('registry')->execute();
+    db_truncate('registry_file')->execute();
+    _registry_parse_files($files);
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    throw $e;
+  }
+  variable_set('registry_rebuild', TRUE);
+}
+
+/**
  * Disable any items in the {system} table that are not core compatible.
  */
 function update_fix_compatibility() {
diff --git a/core/modules/simpletest/tests/registry.test b/core/modules/simpletest/tests/registry.test
index bcd8d4e..df5eed7 100644
--- a/core/modules/simpletest/tests/registry.test
+++ b/core/modules/simpletest/tests/registry.test
@@ -140,3 +140,48 @@ CONTENTS;
   }
 
 }
+
+/**
+ * Test that we can recover from a broken registry.
+ */
+class RegistryRecoveryTestCase extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Registry recover test',
+      'description' => 'Test that we can recover from a broken registry.',
+      'group' => 'System'
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('registry_test');
+    $this->drupalLogin($this->drupalCreateUser(array('administer site configuration', 'administer software updates')));
+  }
+
+  /**
+   * Test that we can recover from a broken registry.
+   */
+  public function testBrokenRegistryRecover() {
+    // Hit front page again, confirm it runs.
+    $this->drupalGet('');
+    $this->assertText('No front page content has been created yet.');
+
+    // Break the registry, and confirm that we get a fatal error.
+    variable_set('clean_url', TRUE);
+    variable_set('registry_test_break_the_registry', TRUE);
+    registry_rebuild();
+    $this->drupalGet('');
+    $this->assertText("Fatal error: Class 'RegistryTestClass' not found");
+
+    // Hit update.php, confirm that we can load the page.
+    $this->drupalGet('core/update.php');
+    $this->assertText("Drupal database update");
+
+    // Hit the front page again, confirm it runs.
+    $this->drupalGet('');
+    $this->assertText('No front page content has been created yet.');
+  }
+}
+
diff --git a/core/update.php b/core/update.php
index dd338a2..bf074a4 100644
--- a/core/update.php
+++ b/core/update.php
@@ -392,6 +392,8 @@ if (empty($op) && update_access_allowed()) {
   // stage, since the real requirements check happens further down.
   update_check_requirements(TRUE);
 
+  update_rebuild_registry();
+
   // Redirect to the update information page if all requirements were met.
   install_goto('core/update.php?op=info');
 }
