diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index 3c8bdf2..e52fc76 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -119,7 +119,11 @@ public function onRespond(FilterResponseEvent $event) {
       $response->headers->set($name, $value, FALSE);
     }
 
-    $is_cacheable = ($this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW) && ($this->responsePolicy->check($response, $request) !== ResponsePolicyInterface::DENY);
+    // Check if the response can be cached, never cache server errors.
+    $is_cacheable = FALSE;
+    if (!$response->isServerError()) {
+      $is_cacheable = ($this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW) && ($this->responsePolicy->check($response, $request) !== ResponsePolicyInterface::DENY);
+    }
 
     // Add headers necessary to specify whether the response should be cached by
     // proxies and/or the browser.
diff --git a/core/lib/Drupal/Core/StackMiddleware/PageCache.php b/core/lib/Drupal/Core/StackMiddleware/PageCache.php
index b381018..6e85963 100644
--- a/core/lib/Drupal/Core/StackMiddleware/PageCache.php
+++ b/core/lib/Drupal/Core/StackMiddleware/PageCache.php
@@ -239,6 +239,11 @@ protected function fetch(Request $request, $type = self::MASTER_REQUEST, $catch
       return $response;
     }
 
+    // Never cache server errors.
+    if ($response->isServerError()) {
+      return $response;
+    }
+
     if ($this->responsePolicy->check($response, $request) === ResponsePolicyInterface::DENY) {
       return $response;
     }
diff --git a/core/modules/system/src/Tests/System/ErrorHandlerTest.php b/core/modules/system/src/Tests/System/ErrorHandlerTest.php
index 597a374..6d353e9 100644
--- a/core/modules/system/src/Tests/System/ErrorHandlerTest.php
+++ b/core/modules/system/src/Tests/System/ErrorHandlerTest.php
@@ -130,6 +130,22 @@ function testExceptionHandler() {
     $this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
     $this->assertErrorMessage($error_renderer_exception);
 
+    // Enable the page cache and disable error reporting, ensure that 5xx
+    // responses are not cached.
+    $config = $this->config('system.performance');
+    $config->set('cache.page.use_internal', 1);
+    $config->set('cache.page.max_age', 300);
+    $config->save();
+    $this->config('system.logging')
+      ->set('error_level', ERROR_REPORTING_HIDE)
+      ->save();
+
+    $this->drupalGet('error-test/trigger-exception');
+    $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
+    $this->assertIdentical(strpos($this->drupalGetHeader('Cache-Control'), 'public'), FALSE, 'Received expected HTTP status line.');
+    $this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
+    $this->assertNoErrorMessage($error_exception);
+
     // The exceptions are expected. Do not interpret them as a test failure.
     // Not using File API; a potential error must trigger a PHP warning.
     unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
