diff --git a/core/includes/update.inc b/core/includes/update.inc
index 022f95011eafc78b4cab7b97e49da7606287af01..d6fa9d6a870ea4669060361c5e942f04399c02b3 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -52,8 +52,12 @@ function update_check_requirements() {
   _update_fix_missing_schema();
 
   // Check requirements of all loaded modules.
-  $requirements = \Drupal::moduleHandler()->invokeAll('requirements', ['update']);
+  $requirements = array_merge(
+    \Drupal::moduleHandler()->invokeAll('requirements', ['update']),
+    \Drupal::moduleHandler()->invokeAll('update_requirements')
+  );
   \Drupal::moduleHandler()->alter('requirements', $requirements);
+  \Drupal::moduleHandler()->alter('update_requirements', $requirements);
   $requirements += update_system_schema_requirements();
   return $requirements;
 }
diff --git a/core/lib/Drupal/Core/Extension/module.api.php b/core/lib/Drupal/Core/Extension/module.api.php
index 88213fafd7262fb1df9fe15104745622b6fabe14..29b8eebe2d53599ece6c9e5e4a3c08e8e59660f6 100644
--- a/core/lib/Drupal/Core/Extension/module.api.php
+++ b/core/lib/Drupal/Core/Extension/module.api.php
@@ -1275,6 +1275,66 @@ function hook_runtime_requirements_alter(array &$requirements): void {
   unset($requirements['foo']);
 }
 
+/**
+ * Check requirements before running database updates.
+ *
+ * This hook is invoked when update.php is run and when database updates are
+ * triggered via the CLI.
+ *
+ * @return array
+ *   An associative array where the keys are arbitrary but must be unique (it
+ *   is suggested to use the module short name as a prefix) and the values are
+ *   themselves associative arrays with the following elements:
+ *   - title: The name of the requirement.
+ *   - value: The current value (e.g., version, time, level, etc).
+ *   - description: The description of the requirement/status.
+ *   - severity: (optional) The requirement's result/severity level, one of:
+ *     - REQUIREMENT_INFO: Has no effect during updates.
+ *     - REQUIREMENT_OK: Has no effect during updates.
+ *     - REQUIREMENT_WARNING: Displays a warning, user can choose to continue.
+ *     - REQUIREMENT_ERROR: Displays an error message, user cannot continue
+ *       until the problem is resolved.
+ *     Defaults to REQUIREMENT_OK.
+ */
+function hook_update_requirements() {
+  $requirements = [];
+
+  // Test PHP version
+  $requirements['php'] = [
+    'title' => t('PHP'),
+    'value' => phpversion(),
+  ];
+  if (version_compare(phpversion(), \Drupal::MINIMUM_PHP) < 0) {
+    $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => \Drupal::MINIMUM_PHP]);
+    $requirements['php']['severity'] = REQUIREMENT_ERROR;
+  }
+
+  return $requirements;
+}
+
+/**
+ * Alters update requirements data.
+ *
+ * Implementations are able to alter the title, value, description or the
+ * severity of certain requirements defined by hook_requirements() and
+ * hook_update_requirements() implementations, or even remove such entries.
+ *
+ * @param array $requirements
+ *   The requirements data to be altered.
+ *
+ * @see hook_update_requirements()
+ */
+function hook_update_requirements_alter(array &$requirements): void {
+  // Change the title from 'PHP' to 'PHP version'.
+  $requirements['php']['title'] = t('PHP version');
+
+  // Decrease the 'update status' requirement severity from warning to info.
+  $requirements['update status']['severity'] = REQUIREMENT_INFO;
+
+  // Remove a requirements entry.
+  unset($requirements['foo']);
+}
+
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/core/modules/system/tests/modules/module_update_requirements/module_update_requirements.info.yml b/core/modules/system/tests/modules/module_update_requirements/module_update_requirements.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..52604b689262e18a658510c1211fd73aeae27b2b
--- /dev/null
+++ b/core/modules/system/tests/modules/module_update_requirements/module_update_requirements.info.yml
@@ -0,0 +1,5 @@
+name: 'Test Hook Update Requirements'
+type: module
+description: 'Support module for testing hook_update_requirements().'
+package: Testing
+version: VERSION
diff --git a/core/modules/system/tests/modules/module_update_requirements/src/Hook/ModuleUpdateRequirementsHooks.php b/core/modules/system/tests/modules/module_update_requirements/src/Hook/ModuleUpdateRequirementsHooks.php
new file mode 100644
index 0000000000000000000000000000000000000000..f0666222f1429549845abcf1ef67a5e6dd685c14
--- /dev/null
+++ b/core/modules/system/tests/modules/module_update_requirements/src/Hook/ModuleUpdateRequirementsHooks.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\module_update_requirements\Hook;
+
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for module_update_requirements.
+ */
+class ModuleUpdateRequirementsHooks {
+
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_update_requirements().
+   */
+  #[Hook('update_requirements')]
+  public function updateRequirements(): array {
+    return [
+      'test.update.error' => [
+        'title' => $this->t('UpdateError'),
+        'value' => $this->t('None'),
+        'description' => $this->t('Update Error.'),
+        'severity' => REQUIREMENT_ERROR,
+      ],
+      'test.update.error.alter' => [
+        'title' => $this->t('UpdateError'),
+        'value' => $this->t('None'),
+        'description' => $this->t('Update Error.'),
+        'severity' => REQUIREMENT_ERROR,
+      ],
+    ];
+  }
+
+  /**
+   * Implements hook_update_requirements_alter().
+   */
+  #[Hook('update_requirements_alter')]
+  public function updateRequirementsAlter(array &$requirements): void {
+    $requirements['test.update.error.alter'] = [
+      'title' => $this->t('UpdateWarning'),
+      'value' => $this->t('None'),
+      'description' => $this->t('Update Warning.'),
+      'severity' => REQUIREMENT_WARNING,
+    ];
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Updater/UpdateRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Updater/UpdateRequirementsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3129361f2a4817536a0c5f6dcdff9d29bc9bbf71
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Updater/UpdateRequirementsTest.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\KernelTests\Core\Updater;
+
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests hook_update_requirements() and hook_update_requirements_alter().
+ *
+ * @group Hooks
+ */
+class UpdateRequirementsTest extends KernelTestBase {
+
+  use StringTranslationTrait;
+
+  /**
+   * Tests hook_update_requirements().
+   */
+  public function testUpdateRequirements(): void {
+    require_once 'core/includes/update.inc';
+
+    \Drupal::service('module_installer')->install(['module_update_requirements']);
+    $testRequirements = [
+      'title' => $this->t('UpdateError'),
+      'value' => $this->t('None'),
+      'description' => $this->t('Update Error.'),
+      'severity' => REQUIREMENT_ERROR,
+    ];
+    $requirements = update_check_requirements()['test.update.error'];
+    $this->assertEquals($testRequirements, $requirements);
+
+    $testAlterRequirements = [
+      'title' => $this->t('UpdateWarning'),
+      'value' => $this->t('None'),
+      'description' => $this->t('Update Warning.'),
+      'severity' => REQUIREMENT_WARNING,
+    ];
+    $alterRequirements = update_check_requirements()['test.update.error.alter'];
+    $this->assertEquals($testAlterRequirements, $alterRequirements);
+  }
+
+}