diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index 73c7139..04a941d 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -48,9 +48,6 @@ class DatabaseBackend implements CacheBackendInterface {
    */
   function getMultiple(&$cids) {
     try {
-      // Garbage collection necessary when enforcing a minimum cache lifetime.
-      $this->garbageCollection($this->bin);
-
       // When serving cached pages, the overhead of using db_select() was found
       // to add around 30% overhead to the request. Since $this->bin is a
       // variable, this means the call to db_query() here uses a concatenated
@@ -185,30 +182,28 @@ class DatabaseBackend implements CacheBackendInterface {
    * Implements Drupal\Core\Cache\CacheBackendInterface::expire().
    */
   function expire() {
-    if (variable_get('cache_lifetime', 0)) {
+    if ($cache_lifetime = variable_get('cache_lifetime', 0)) {
       // We store the time in the current user's $user->cache variable which
       // will be saved into the sessions bin by _drupal_session_write(). We then
       // simulate that the cache was flushed for this user by not returning
       // cached data that was cached before the timestamp.
       $GLOBALS['user']->cache = REQUEST_TIME;
 
-      $cache_flush = variable_get('cache_flush_' . $this->bin, 0);
-      if ($cache_flush == 0) {
-        // This is the first request to clear the cache, start a timer.
-        variable_set('cache_flush_' . $this->bin, REQUEST_TIME);
-      }
-      elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
-        // Clear the cache for everyone; cache_lifetime seconds have passed
-        // since the first request to clear the cache.
-        db_delete($this->bin)
-          ->condition('expire', CACHE_PERMANENT, '<>')
-          ->condition('expire', REQUEST_TIME, '<')
-          ->execute();
-        variable_set('cache_flush_' . $this->bin, 0);
-      }
+      // Clear expired items from the cache.
+      db_delete($this->bin)
+        ->condition('expire', CACHE_PERMANENT, '>')
+        ->condition('expire', REQUEST_TIME, '<')
+        ->execute();
+      variable_set('cache_flush_' . $this->bin, 0);
+
+      // Clear CACHE_TEMPORARY items that are older than the minimum cache lifetime.
+      db_delete($this->bin)
+        ->condition('expire', CACHE_TEMPORARY)
+        ->condition('created', REQUEST_TIME - $cache_lifetime, '<')
+        ->execute();
     }
     else {
-      // No minimum cache lifetime, flush all temporary cache entries now.
+      // No minimum cache lifetime, flush all expired and temporary cache entries now.
       db_delete($this->bin)
         ->condition('expire', CACHE_PERMANENT, '<>')
         ->condition('expire', REQUEST_TIME, '<')
@@ -222,18 +217,7 @@ class DatabaseBackend implements CacheBackendInterface {
   function garbageCollection() {
     global $user;
 
-    // When cache lifetime is in force, avoid running garbage collection too
-    // often since this will remove temporary cache items indiscriminately.
-    $cache_flush = variable_get('cache_flush_' . $this->bin, 0);
-    if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
-      // Reset the variable immediately to prevent a meltdown in heavy load situations.
-      variable_set('cache_flush_' . $this->bin, 0);
-      // Time to flush old cache data
-      db_delete($this->bin)
-        ->condition('expire', CACHE_PERMANENT, '<>')
-        ->condition('expire', $cache_flush, '<=')
-        ->execute();
-    }
+    $this->expire();
   }
 
   /**
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 2cbb615..283f5b3 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -682,7 +682,7 @@ function system_schema() {
       ),
     ),
     'indexes' => array(
-      'expire' => array('expire'),
+      'expire_created' => array('expire', 'created'),
     ),
     'primary key' => array('cid'),
   );
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 469f996..761ef5a 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -3057,7 +3057,17 @@ function system_cron() {
   $core = array('cache', 'path', 'filter', 'page', 'form', 'menu');
   $cache_bins = array_merge(module_invoke_all('flush_caches'), $core);
   foreach ($cache_bins as $bin) {
-    cache($bin)->expire();
+    // If the cache backend provides a garbageCollection() method, call that.
+    // If it does not, expire all temporary and expired cache items. Limit
+    // these calls to once every 24 hours by default to avoid wiping the page
+    // and block caches every cron run.
+    $cache = cache($bin);
+    $name = 'cache_garbage_collect_' . $bin;
+    $window = max(variable_get('cache_lifetime', 0), variable_get('cache_garbage_collection_frequency', 86400));
+    if (flood_is_allowed($name, 1, $window, 'cron')) {
+      flood_register_event($name, 1, $window, 'cron');
+      $cache->garbageCollection();
+    }
   }
 
   // Cleanup the batch table and the queue for failed batches.
