diff --git a/core/lib/Drupal/Core/Extension/module.api.php b/core/lib/Drupal/Core/Extension/module.api.php
index a30fc7a80d2cbead75e222d986a1934343562b52..88213fafd7262fb1df9fe15104745622b6fabe14 100644
--- a/core/lib/Drupal/Core/Extension/module.api.php
+++ b/core/lib/Drupal/Core/Extension/module.api.php
@@ -1187,6 +1187,94 @@ function hook_requirements_alter(array &$requirements): void {
   unset($requirements['foo']);
 }
 
+/**
+ * Check runtime requirements and do status reporting.
+ *
+ * Requirements are displayed on the 'Status report' (/admin/reports/status).
+ *
+ * Runtime requirements do not impact installation or updates of modules that
+ * define them. These requirements are only used to display information on the
+ * status report but do not impact site behavior. They can be used for more
+ * general status information like maintenance tasks and security issues.
+ * The returned requirements will be listed on the status report in the
+ * administration section, with an indication of the severity level.
+ * Moreover, any requirement with a severity of REQUIREMENT_ERROR will result in
+ * a notice on the 'Configuration' administration page (/admin/config).
+ *
+ * @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 severity level, one of:
+ *     - REQUIREMENT_INFO: For info only.
+ *     - REQUIREMENT_OK: The requirement is satisfied.
+ *     - REQUIREMENT_WARNING: The requirement failed with a warning.
+ *     - REQUIREMENT_ERROR: The requirement failed with an error.
+ *     Defaults to REQUIREMENT_OK.
+ */
+function hook_runtime_requirements(): array {
+  $requirements = [];
+
+  // Report Drupal version
+  $requirements['drupal'] = [
+    'title' => t('Drupal'),
+    'value' => \Drupal::VERSION,
+    'severity' => REQUIREMENT_INFO,
+  ];
+
+  // Test PHP version
+  $requirements['php'] = [
+    'title' => t('PHP'),
+    'value' => Link::fromTextAndUrl(phpversion(), Url::fromRoute('system.php'))->toString(),
+  ];
+  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;
+  }
+
+  // Report cron status
+  $cron_last = \Drupal::state()->get('system.cron_last');
+  $requirements['cron']['title'] = t('Cron maintenance tasks');
+  if (is_numeric($cron_last)) {
+    $requirements['cron']['description'] = '';
+    $requirements['cron']['value'] = t('Last run @time ago', ['@time' => \Drupal::service('date.formatter')->formatTimeDiffSince($cron_last)]);
+  }
+  else {
+    $requirements['cron']['description'] = t('Cron has not run. It appears cron jobs have not been setup on your system. Check the help pages for <a href=":url">configuring cron jobs</a>.', [':url' => 'https://www.drupal.org/docs/administering-a-drupal-site/cron-automated-tasks/cron-automated-tasks-overview']);
+    $requirements['cron']['value'] = t('Never run');
+    $requirements['cron']['severity'] = REQUIREMENT_ERROR;
+  }
+  $requirements['cron']['description'] .= ' ' . t('You can <a href=":cron">run cron manually</a>.', [':cron' => Url::fromRoute('system.run_cron')->toString()]);
+
+  return $requirements;
+}
+
+/**
+ * Alters runtime requirements data.
+ *
+ * Implementations are able to alter the title, value, description or the
+ * severity of certain requirements defined by hook_requirements() and
+ * hook_runtime_requirements() implementations, or even remove such entries.
+ *
+ * @param array $requirements
+ *   The requirements data to be altered.
+ *
+ * @see hook_runtime_requirements()
+ */
+function hook_runtime_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/file/file.install b/core/modules/file/file.install
index bce27470f19d6eb8c342c28ef390cf3b292243f0..18f31ada4c4cf9fc7b47426784f293a4950ca2dc 100644
--- a/core/modules/file/file.install
+++ b/core/modules/file/file.install
@@ -57,54 +57,6 @@ function file_schema(): array {
   return $schema;
 }
 
-/**
- * Implements hook_requirements().
- *
- * Display information about getting upload progress bars working.
- */
-function file_requirements($phase): array {
-  $requirements = [];
-
-  if ($phase != 'runtime') {
-    return $requirements;
-  }
-
-  $server_software = \Drupal::request()->server->get('SERVER_SOFTWARE', '');
-
-  // Get the web server identity.
-  $is_nginx = preg_match("/Nginx/i", $server_software);
-  $is_apache = preg_match("/Apache/i", $server_software);
-  $fastcgi = $is_apache && ((str_contains($server_software, 'mod_fastcgi') || str_contains($server_software, 'mod_fcgi')));
-
-  // Check the uploadprogress extension is loaded.
-  if (extension_loaded('uploadprogress')) {
-    $value = t('Enabled (<a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>)');
-    $description = NULL;
-  }
-  else {
-    $value = t('Not enabled');
-    $description = t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.');
-  }
-
-  // Adjust the requirement depending on what the server supports.
-  if (!$is_apache && !$is_nginx) {
-    $value = t('Not enabled');
-    $description = t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php or Nginx with PHP-FPM.');
-  }
-  elseif ($fastcgi) {
-    $value = t('Not enabled');
-    $description = t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.');
-  }
-
-  $requirements['file_progress'] = [
-    'title' => t('Upload progress'),
-    'value' => $value,
-    'description' => $description,
-  ];
-
-  return $requirements;
-}
-
 /**
  * Implements hook_update_last_removed().
  */
diff --git a/core/modules/file/src/Hook/FileRequirements.php b/core/modules/file/src/Hook/FileRequirements.php
new file mode 100644
index 0000000000000000000000000000000000000000..df6ae2f42a11717328ddce5eda519c9e9be3d544
--- /dev/null
+++ b/core/modules/file/src/Hook/FileRequirements.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\file\Hook;
+
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Requirements for the File module.
+ */
+class FileRequirements {
+
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_runtime_requirements().
+   */
+  #[Hook('runtime_requirements')]
+  public function runtime(): array {
+    $requirements = [];
+    $server_software = \Drupal::request()->server->get('SERVER_SOFTWARE', '');
+
+    // Get the web server identity.
+    $is_nginx = preg_match("/Nginx/i", $server_software);
+    $is_apache = preg_match("/Apache/i", $server_software);
+    $fastcgi = $is_apache && ((str_contains($server_software, 'mod_fastcgi') || str_contains($server_software, 'mod_fcgi')));
+
+    // Check the uploadprogress extension is loaded.
+    if (extension_loaded('uploadprogress')) {
+      $value = $this->t('Enabled (<a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>)');
+      $description = NULL;
+    }
+    else {
+      $value = $this->t('Not enabled');
+      $description = $this->t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.');
+    }
+
+    // Adjust the requirement depending on what the server supports.
+    if (!$is_apache && !$is_nginx) {
+      $value = $this->t('Not enabled');
+      $description = $this->t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php or Nginx with PHP-FPM.');
+    }
+    elseif ($fastcgi) {
+      $value = $this->t('Not enabled');
+      $description = $this->t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.');
+    }
+
+    $requirements['file_progress'] = [
+      'title' => $this->t('Upload progress'),
+      'value' => $value,
+      'description' => $description,
+    ];
+
+    return $requirements;
+  }
+
+}
diff --git a/core/modules/file/tests/src/Kernel/RequirementsTest.php b/core/modules/file/tests/src/Kernel/RequirementsTest.php
index 224616e089b8bc57714db9a0c42da563953b9a81..3cf85346bca4406853319262abfe83be2ccbf185 100644
--- a/core/modules/file/tests/src/Kernel/RequirementsTest.php
+++ b/core/modules/file/tests/src/Kernel/RequirementsTest.php
@@ -32,11 +32,10 @@ public function testUploadRequirements(): void {
 
     /** @var \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler */
     $moduleHandler = $this->container->get('module_handler');
-    $moduleHandler->loadInclude('file', 'install');
 
     // Test unspecified server software.
     $this->setServerSoftware(NULL);
-    $requirements = \file_requirements('runtime');
+    $requirements = $moduleHandler->invoke('file', 'runtime_requirements');
     $this->assertNotEmpty($requirements);
 
     $this->assertEquals('Upload progress', (string) $requirements['file_progress']['title']);
@@ -45,21 +44,21 @@ public function testUploadRequirements(): void {
 
     // Test Apache + mod_php.
     $this->setServerSoftware('Apache mod_php');
-    $requirements = \file_requirements('runtime');
+    $requirements = $moduleHandler->invoke('file', 'runtime_requirements');
     $this->assertNotEmpty($requirements);
     $this->assertEquals('Not enabled', (string) $requirements['file_progress']['value']);
     $this->assertEquals('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.', (string) $requirements['file_progress']['description']);
 
     // Test Apache + mod_fastcgi.
     $this->setServerSoftware('Apache mod_fastcgi');
-    $requirements = \file_requirements('runtime');
+    $requirements = $moduleHandler->invoke('file', 'runtime_requirements');
     $this->assertNotEmpty($requirements);
     $this->assertEquals('Not enabled', (string) $requirements['file_progress']['value']);
     $this->assertEquals('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.', (string) $requirements['file_progress']['description']);
 
     // Test Nginx.
     $this->setServerSoftware('Nginx');
-    $requirements = \file_requirements('runtime');
+    $requirements = $moduleHandler->invoke('file', 'runtime_requirements');
     $this->assertNotEmpty($requirements);
     $this->assertEquals('Not enabled', (string) $requirements['file_progress']['value']);
     $this->assertEquals('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.', (string) $requirements['file_progress']['description']);
diff --git a/core/modules/system/src/SystemManager.php b/core/modules/system/src/SystemManager.php
index 9e3d61ef3f9f173b85c929f765f604551a03d47b..44305e80ef3044e5fc6a3666ab0ed35b9c42c1d7 100644
--- a/core/modules/system/src/SystemManager.php
+++ b/core/modules/system/src/SystemManager.php
@@ -107,7 +107,10 @@ public function listRequirements() {
 
     // Check run-time requirements and status information.
     $requirements = $this->moduleHandler->invokeAll('requirements', ['runtime']);
+    $runtime_requirements = $this->moduleHandler->invokeAll('runtime_requirements');
+    $requirements = array_merge($requirements, $runtime_requirements);
     $this->moduleHandler->alter('requirements', $requirements);
+    $this->moduleHandler->alter('runtime_requirements', $requirements);
     uasort($requirements, function ($a, $b) {
       if (!isset($a['weight'])) {
         if (!isset($b['weight'])) {
diff --git a/core/modules/system/tests/modules/module_runtime_requirements/module_runtime_requirements.info.yml b/core/modules/system/tests/modules/module_runtime_requirements/module_runtime_requirements.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0c1567542e67c743f8d197b229eb1eb36596183a
--- /dev/null
+++ b/core/modules/system/tests/modules/module_runtime_requirements/module_runtime_requirements.info.yml
@@ -0,0 +1,5 @@
+name: 'Test Hook Runtime Requirements'
+type: module
+description: 'Support module for testing hook_runtime_requirements().'
+package: Testing
+version: VERSION
diff --git a/core/modules/system/tests/modules/module_runtime_requirements/src/Hook/ModuleRuntimeRequirementsHooks.php b/core/modules/system/tests/modules/module_runtime_requirements/src/Hook/ModuleRuntimeRequirementsHooks.php
new file mode 100644
index 0000000000000000000000000000000000000000..0fa4b2f6f804235c6e3fd0a0e82fb8030b57cb70
--- /dev/null
+++ b/core/modules/system/tests/modules/module_runtime_requirements/src/Hook/ModuleRuntimeRequirementsHooks.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\module_runtime_requirements\Hook;
+
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for module_runtime_requirements.
+ */
+class ModuleRuntimeRequirementsHooks {
+
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_runtime_requirements().
+   */
+  #[Hook('runtime_requirements')]
+  public function runtimeRequirements(): array {
+    return [
+      'test.runtime.error' => [
+        'title' => $this->t('RuntimeError'),
+        'value' => $this->t('None'),
+        'description' => $this->t('Runtime Error.'),
+        'severity' => REQUIREMENT_ERROR,
+      ],
+      'test.runtime.error.alter' => [
+        'title' => $this->t('RuntimeError'),
+        'value' => $this->t('None'),
+        'description' => $this->t('Runtime Error.'),
+        'severity' => REQUIREMENT_ERROR,
+      ],
+    ];
+  }
+
+  /**
+   * Implements hook_runtime_requirements_alter().
+   */
+  #[Hook('runtime_requirements_alter')]
+  public function runtimeRequirementsAlter(array &$requirements): void {
+    $requirements['test.runtime.error.alter'] = [
+      'title' => $this->t('RuntimeWarning'),
+      'value' => $this->t('None'),
+      'description' => $this->t('Runtime Warning.'),
+      'severity' => REQUIREMENT_WARNING,
+    ];
+  }
+
+}
diff --git a/core/modules/system/tests/src/Kernel/System/RunTimeRequirementsTest.php b/core/modules/system/tests/src/Kernel/System/RunTimeRequirementsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c5577601166cd4285e26d106c07807b7d0d28a4
--- /dev/null
+++ b/core/modules/system/tests/src/Kernel/System/RunTimeRequirementsTest.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\system\Kernel\System;
+
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the effectiveness of hook_runtime_requirements().
+ *
+ * @group system
+ */
+class RunTimeRequirementsTest extends KernelTestBase {
+
+  use StringTranslationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['system'];
+
+  /**
+   * Tests hook_runtime_requirements() and hook_runtime_requirements_alter().
+   */
+  public function testRuntimeRequirements(): void {
+    // Enable the test module.
+    \Drupal::service('module_installer')->install(['module_runtime_requirements']);
+    $testRequirements = [
+      'title' => $this->t('RuntimeError'),
+      'value' => $this->t('None'),
+      'description' => $this->t('Runtime Error.'),
+      'severity' => REQUIREMENT_ERROR,
+    ];
+    $requirements = \Drupal::service('system.manager')->listRequirements()['test.runtime.error'];
+    $this->assertEquals($testRequirements, $requirements);
+
+    $testRequirementsAlter = [
+      'title' => $this->t('RuntimeWarning'),
+      'value' => $this->t('None'),
+      'description' => $this->t('Runtime Warning.'),
+      'severity' => REQUIREMENT_WARNING,
+    ];
+    $requirementsAlter = \Drupal::service('system.manager')->listRequirements()['test.runtime.error.alter'];
+    $this->assertEquals($testRequirementsAlter, $requirementsAlter);
+  }
+
+}