diff --git a/lib/setup.php b/lib/setup.php
index 419f83fb172..306a9642f77 100644
--- a/lib/setup.php
+++ b/lib/setup.php
@@ -666,6 +666,12 @@ $bootstrapcachefile = $CFG->localcachedir . '/bootstrap.php';
 if (is_readable($bootstrapcachefile)) {
     try {
         require_once($bootstrapcachefile);
+        // Verify the file is not stale.
+        if (!isset($CFG->bootstraphash) || $CFG->bootstraphash !== hash_local_config_cache()) {
+            // Something has changed, the bootstrap.php file is stale.
+            unset($CFG->siteidentifier);
+            @unlink($bootstrapcachefile);
+        }
     } catch (Throwable $e) {
         // If it is corrupted then attempt to delete it and it will be rebuilt.
         @unlink($bootstrapcachefile);
diff --git a/lib/setuplib.php b/lib/setuplib.php
index ddcc4b04d1b..040d589965c 100644
--- a/lib/setuplib.php
+++ b/lib/setuplib.php
@@ -809,7 +809,11 @@ function initialise_local_config_cache() {
         $contents = "<?php
 // ********** This file is generated DO NOT EDIT **********
 \$CFG->siteidentifier = '" . addslashes($CFG->siteidentifier) . "';
-define('SYSCONTEXTID', ".SYSCONTEXTID.");
+\$CFG->bootstraphash = '" . hash_local_config_cache() . "';
+// Only if the file is not stale and has not been defined.
+if (\$CFG->bootstraphash === hash_local_config_cache() && !defined('SYSCONTEXTID')) {
+    define('SYSCONTEXTID', ".SYSCONTEXTID.");
+}
 ";
 
         $temp = $bootstrapcachefile . '.tmp' . uniqid();
@@ -819,6 +823,25 @@ define('SYSCONTEXTID', ".SYSCONTEXTID.");
     }
 }
 
+/**
+ * Calculate a proper hash to be able to invalidate stale cached configs.
+ *
+ * Only to be used to verify bootstrap.php status.
+ *
+ * @return string md5 hash of all the sensible bits deciding if cached config is stale or no.
+ */
+function hash_local_config_cache() {
+    global $CFG;
+
+    // This is pretty much {@see moodle_database::get_settings_hash()} that is used
+    // as identifier for the database meta information MUC cache. Should be enough to
+    // react against any of the normal changes (new prefix, change of DB type) while
+    // *incorrectly* keeping the old dataroot directory unmodified with stale data.
+    // This may need more stuff to be considered if it's discovered that there are
+    // more variables making the file stale.
+    return md5($CFG->dbtype . $CFG->dbhost . $CFG->dbuser . $CFG->dbname . $CFG->prefix);
+}
+
 /**
  * Initialises $FULLME and friends. Private function. Should only be called from
  * setup.php.