diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index fb2f3484b7..fb49c8afeb 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -930,16 +930,29 @@ function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $va
   // Check for file upload errors and return FALSE for this file if a lower
   // level system error occurred. For a complete list of errors:
   // See http://php.net/manual/features.file-upload.errors.php.
+  $error_to_log = NULL;
   switch ($file_info->getError()) {
     case UPLOAD_ERR_INI_SIZE:
     case UPLOAD_ERR_FORM_SIZE:
-      \Drupal::messenger()->addError(t('The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.', ['%file' => $original_file_name, '%maxsize' => format_size(Environment::getUploadMaxSize())]));
-      return FALSE;
+      $error_to_log = "The file $original_file_name could not be saved because it exceeds " . format_size(Environment::getUploadMaxSize()) . ", the maximum allowed size for uploads.";
+      break;
 
     case UPLOAD_ERR_PARTIAL:
     case UPLOAD_ERR_NO_FILE:
-      \Drupal::messenger()->addError(t('The file %file could not be saved because the upload did not complete.', ['%file' => $original_file_name]));
-      return FALSE;
+      $error_to_log = "The file $original_file_name could not be saved because the upload did not complete.";
+      break;
+
+    case UPLOAD_ERR_NO_TMP_DIR:
+      $error_to_log = "The file $original_file_name could not be saved because the server is missing a temporary folder.";
+      break;
+
+    case UPLOAD_ERR_CANT_WRITE:
+      $error_to_log = "The file $original_file_name could not be saved because the server is unable to write to disk.";
+      break;
+
+    case UPLOAD_ERR_EXTENSION:
+      $error_to_log = "The file $original_file_name could not be saved because a PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with phpinfo() may help.";
+      break;
 
     case UPLOAD_ERR_OK:
       // Final check that this is a valid upload, if it isn't, use the
@@ -950,9 +963,17 @@ function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $va
 
     default:
       // Unknown error
-      \Drupal::messenger()->addError(t('The file %file could not be saved. An unknown error has occurred.', ['%file' => $original_file_name]));
-      return FALSE;
-
+      $error_to_log = 'The file ' . $file_info->getFilename() . ' could not be saved. An unknown error has occurred.';
+      break;
+  }
+  if (isset($error_to_log)) {
+    // Unconditionally display an error message to the end user. This is a
+    // generic message since the errors that trigger this represent server-level
+    // problems that end users should not know about (and cannot fix by
+    // attempting the upload again).
+    \Drupal::messenger()->addError(t('The file %file could not be saved. An unknown error has occurred.', ['%file' => $original_file_name]));
+    \Drupal::logger('file')->error($error_to_log);
+    return FALSE;
   }
 
   // Build a list of allowed extensions.
diff --git a/core/modules/file/tests/src/Kernel/FileModuleTest.php b/core/modules/file/tests/src/Kernel/FileModuleTest.php
index de15467832..90940d2261 100644
--- a/core/modules/file/tests/src/Kernel/FileModuleTest.php
+++ b/core/modules/file/tests/src/Kernel/FileModuleTest.php
@@ -17,21 +17,80 @@ class FileModuleTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected static $modules = ['file'];
+  protected static $modules = ['dblog', 'file'];
 
   /**
    * Tests file size upload errors.
    *
-   * @throws \Drupal\Core\Entity\EntityStorageException
+   * @dataProvider providerFileSaveUploadSingle
    */
-  public function testFileSaveUploadSingleErrorFormSize() {
+  public function testFileSaveUploadSingle($error, $expected_log_message) {
+    $this->installSchema('dblog', ['watchdog']);
+
     $file_name = $this->randomMachineName();
     $file_info = $this->createMock(UploadedFile::class);
-    $file_info->expects($this->once())->method('getError')->willReturn(UPLOAD_ERR_FORM_SIZE);
+    $file_info->expects($this->once())->method('getError')->willReturn($error);
     $file_info->expects($this->once())->method('getClientOriginalName')->willReturn($file_name);
+
+    // Confirm the upload failed.
     $this->assertFalse(\_file_save_upload_single($file_info, 'name'));
-    $expected_message = new TranslatableMarkup('The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.', ['%file' => $file_name, '%maxsize' => format_size(Environment::getUploadMaxSize())]);
+
+    // Check the displayed user message.
+    $expected_message = new TranslatableMarkup("The file %file could not be saved. An unknown error has occurred.", ['%file' => $file_name]);
     $this->assertEquals($expected_message, \Drupal::messenger()->all()['error'][0]);
+
+    // Check the logged message.
+    $results = \Drupal::database()->select('watchdog', 'w')
+      ->fields('w')
+      ->execute()
+      ->fetchAll();
+    $actual_log_message = $results[0]->message;
+    if ($error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE) {
+      $upload_size = format_size(Environment::getUploadMaxSize())->render();
+      $expected_log_message = sprintf($expected_log_message, $file_name, $upload_size);
+    }
+    else {
+      $expected_log_message = sprintf($expected_log_message, $file_name);
+    }
+    $this->assertSame($expected_log_message, $actual_log_message);
+  }
+
+  /**
+   * Data provider for testFileSaveUploadSingle.
+   */
+  public function providerFileSaveUploadSingle() {
+
+    return [
+      [
+        UPLOAD_ERR_INI_SIZE,
+        'The file %s could not be saved because it exceeds %s, the maximum allowed size for uploads.',
+      ],
+      [
+        UPLOAD_ERR_FORM_SIZE,
+        'The file %s could not be saved because it exceeds %s, the maximum allowed size for uploads.',
+      ],
+      [
+        UPLOAD_ERR_PARTIAL,
+        'The file %s could not be saved because the upload did not complete.',
+      ],
+      [
+        UPLOAD_ERR_NO_FILE,
+        'The file %s could not be saved because the upload did not complete.',
+      ],
+      [
+        UPLOAD_ERR_NO_TMP_DIR,
+        'The file %s could not be saved because the server is missing a temporary folder.',
+      ],
+      [
+        UPLOAD_ERR_CANT_WRITE,
+        'The file %s could not be saved because the server is unable to write to disk.',
+      ],
+      [
+        UPLOAD_ERR_EXTENSION,
+        'The file %s could not be saved because a PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with phpinfo() may help.',
+      ],
+    ];
+
   }
 
 }
