diff --git a/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php b/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php
index 37a3e05250c5f0ab59c5fa4a9c5e6153a696cc34..f27cc7f3315a67be667e084790584f41463f91d3 100644
--- a/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php
+++ b/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php
@@ -57,6 +57,13 @@ class SiteConfiguration implements SingletonInterface
      */
     protected $configFileName = 'config.yaml';
 
+    /**
+     * YAML file name with all settings.
+     *
+     * @internal
+     */
+    protected string $settingsFileName = 'settings.yaml';
+
     /**
      * Identifier to store all configuration data in cache_core cache.
      *
@@ -148,6 +155,7 @@ class SiteConfiguration implements SingletonInterface
         $sites = [];
         $siteConfiguration = $this->getAllSiteConfigurationFromFiles($useCache);
         foreach ($siteConfiguration as $identifier => $configuration) {
+            $configuration['settings'] = $this->getSiteSettings($identifier, $configuration);
             $rootPageId = (int)($configuration['rootPageId'] ?? 0);
             if ($rootPageId > 0) {
                 $sites[$identifier] = GeneralUtility::makeInstance(Site::class, $identifier, $rootPageId, $configuration);
@@ -157,6 +165,28 @@ class SiteConfiguration implements SingletonInterface
         return $sites;
     }
 
+    /**
+     * Returns an array of paths in which a site configuration is found.
+     *
+     * @internal
+     */
+    public function getAllSiteConfigurationPaths(): array
+    {
+        $finder = new Finder();
+        $paths = [];
+        try {
+            $finder->files()->depth(0)->name($this->configFileName)->in($this->configPath . '/*');
+        } catch (\InvalidArgumentException $e) {
+            $finder = [];
+        }
+
+        foreach ($finder as $fileInfo) {
+            $path = $fileInfo->getPath();
+            $paths[basename($path)] = $path;
+        }
+        return $paths;
+    }
+
     /**
      * Read the site configuration from config files.
      *
@@ -208,6 +238,25 @@ class SiteConfiguration implements SingletonInterface
         return $loader->load(GeneralUtility::fixWindowsFilePath($fileName), YamlFileLoader::PROCESS_IMPORTS);
     }
 
+    protected function getSiteSettings(string $siteIdentifier, array $siteConfiguration): array
+    {
+        $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->settingsFileName;
+        if (file_exists($fileName)) {
+            $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
+            return $loader->load(GeneralUtility::fixWindowsFilePath($fileName), YamlFileLoader::PROCESS_IMPORTS);
+        }
+        return $siteConfiguration['settings'] ?? [];
+    }
+
+    public function writeSettings(string $siteIdentifier, array $settings): void
+    {
+        $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->settingsFileName;
+        $yamlFileContents = Yaml::dump($settings, 99, 2);
+        if (!GeneralUtility::writeFile($fileName, $yamlFileContents)) {
+            throw new SiteConfigurationWriteException('Unable to write site settings in sites/' . $siteIdentifier . '/' . $this->configFileName, 1590487411);
+        }
+    }
+
     /**
      * Add or update a site configuration
      *
diff --git a/typo3/sysext/core/Documentation/Changelog/12.1/Feature-99047-LoadSiteSettingsFromSeparateSettingsyaml.rst b/typo3/sysext/core/Documentation/Changelog/12.1/Feature-99047-LoadSiteSettingsFromSeparateSettingsyaml.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b8f72864454e31233dce67ba6419c6ce89623698
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/12.1/Feature-99047-LoadSiteSettingsFromSeparateSettingsyaml.rst
@@ -0,0 +1,38 @@
+.. include:: /Includes.rst.txt
+
+.. _feature-99047-1668081474:
+
+================================================================
+Feature: #99047 - Load site settings from separate settings.yaml
+================================================================
+
+See :issue:`99047`
+
+Description
+===========
+
+Site Settings have been introduced with TYPO3 v10 as part of the configuration
+of a site. In contrast to the site configuration, they are mostly used to
+provide sane defaults for TypoScript constants and have a layer of arbitrary
+configuration available in any context.
+
+In order to separate these settings from the system site configuration, make them
+accessible and editable in the TYPO3 Backend, and to distinguish between required
+site configuration and optional settings, the "settings" part of the settings are
+moved to a separate "settings.yaml" file in the site configuration folder.
+
+A migration wizard is provided as upgrade wizard to migrate settings into the
+new file.
+
+
+Impact
+======
+
+Settings are now loaded from a separate file called "settings.yaml" residing
+next to the :file:`config.yaml` of a site.
+Executing the upgrade wizard will load all settings of a site and create that
+file for the user. The migration wizard will not remove / rewrite the
+:file:`config.yaml` - the user should do that on their own, to avoid breaking
+custom-built functionality.
+
+.. index:: Backend, YAML, ext:core
diff --git a/typo3/sysext/install/Classes/Updates/MigrateSiteSettingsConfigUpdate.php b/typo3/sysext/install/Classes/Updates/MigrateSiteSettingsConfigUpdate.php
new file mode 100644
index 0000000000000000000000000000000000000000..cbe7b59fc9f58aee1453c0cf2d355452f1fed4a5
--- /dev/null
+++ b/typo3/sysext/install/Classes/Updates/MigrateSiteSettingsConfigUpdate.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Install\Updates;
+
+use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
+use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * @internal
+ *
+ * The upgrade wizard cuts the settings part of the config.yaml and moves it into settings.yaml.
+ */
+class MigrateSiteSettingsConfigUpdate implements UpgradeWizardInterface
+{
+    protected const SETTINGS_FILENAME = 'settings.yaml';
+
+    protected ?SiteConfiguration $siteConfiguration = null;
+    protected array $sitePathsToMigrate = [];
+
+    public function __construct()
+    {
+        $this->siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
+        $this->sitePathsToMigrate = $this->getSitePathsToMigrate();
+    }
+
+    public function getIdentifier(): string
+    {
+        return 'migrateSiteSettings';
+    }
+
+    public function getTitle(): string
+    {
+        return 'Migrate site settings to separate file';
+    }
+
+    public function getDescription(): string
+    {
+        return
+            'If site settings exist in a config.yaml file, this wizard migrates them to a dedicated settings.yaml file. ' .
+            'Please note that you should remove them from your existing config manually.';
+    }
+
+    public function executeUpdate(): bool
+    {
+        try {
+            foreach ($this->sitePathsToMigrate as $siteIdentifier => $settings) {
+                $this->siteConfiguration->writeSettings($siteIdentifier, $settings);
+            }
+        } catch (SiteConfigurationWriteException $e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * if the settings file does not exist an update is considered as necessary
+     *
+     * @return bool
+     */
+    public function updateNecessary(): bool
+    {
+        return $this->sitePathsToMigrate !== [];
+    }
+
+    public function getPrerequisites(): array
+    {
+        return [];
+    }
+
+    /**
+     * returns an array of siteconfigs, if they don't have a corresponding settings file
+     */
+    protected function getSitePathsToMigrate(): array
+    {
+        $settingsCollection = [];
+        foreach ($this->siteConfiguration->getAllSiteConfigurationPaths() as $siteIdentifier => $configurationPath) {
+            // settings.yaml already exists, skip
+            if (file_exists($configurationPath . '/' . self::SETTINGS_FILENAME)) {
+                continue;
+            }
+            // Check if the site has any settings
+            $siteConfiguration = $this->siteConfiguration->load($siteIdentifier);
+            if (!isset($siteConfiguration['settings'])) {
+                continue;
+            }
+            $settingsCollection[$siteIdentifier] = $siteConfiguration['settings'];
+        }
+        return $settingsCollection;
+    }
+}
diff --git a/typo3/sysext/install/Tests/Functional/Updates/MigrateSiteSettingsConfigUpdateTest.php b/typo3/sysext/install/Tests/Functional/Updates/MigrateSiteSettingsConfigUpdateTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2151ea094f7cc6d64c16b7d24c2ad7763c4d25aa
--- /dev/null
+++ b/typo3/sysext/install/Tests/Functional/Updates/MigrateSiteSettingsConfigUpdateTest.php
@@ -0,0 +1,110 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Install\Tests\Functional\Updates;
+
+use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Updates\MigrateSiteSettingsConfigUpdate;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+class MigrateSiteSettingsConfigUpdateTest extends FunctionalTestCase
+{
+    /**
+     * @test
+     */
+    public function upgradeSettingsUpdateWithSettings(): void
+    {
+        $siteconfigurationIdentifier = 'settings';
+
+        GeneralUtility::makeInstance(SiteConfiguration::class)->write(
+            $siteconfigurationIdentifier,
+            [
+                'rootPageId' => 1,
+                'base' => 'www.test.org',
+                'languages' => [
+                    0 => [
+                        'title' => 'English',
+                        'enabled' => true,
+                        'languageId' => 0,
+                        'base' => '/',
+                        'typo3Language' => 'default',
+                        'locale' => 'en_US.UTF-8',
+                        'iso-639-1' => 'en',
+                        'navigationTitle' => 'English',
+                        'hreflang' => 'en-us',
+                        'direction' => 'ltr',
+                        'flag' => 'us',
+                    ],
+                ],
+                'settings' => [
+                    'debug' => 1,
+                    'test' => true,
+                ],
+                'errorHandling' => [],
+                'routes' => [],
+            ]
+        );
+
+        $subject = new MigrateSiteSettingsConfigUpdate();
+        $subject->executeUpdate();
+        self::assertFileExists($this->getSettingsFilePath($siteconfigurationIdentifier));
+    }
+
+    /**
+     * @test
+     */
+    public function upgradeSettingsUpdateWithoutSettings(): void
+    {
+        $siteconfigurationIdentifier = 'withoutSettings';
+
+        GeneralUtility::makeInstance(SiteConfiguration::class)->write(
+            $siteconfigurationIdentifier,
+            [
+                'rootPageId' => 2,
+                'base' => 'www.testTwo.org',
+                'languages' => [
+                    0 => [
+                        'title' => 'English',
+                        'enabled' => true,
+                        'languageId' => 0,
+                        'base' => '/',
+                        'typo3Language' => 'default',
+                        'locale' => 'en_US.UTF-8',
+                        'iso-639-1' => 'en',
+                        'navigationTitle' => 'English',
+                        'hreflang' => 'en-us',
+                        'direction' => 'ltr',
+                        'flag' => 'us',
+                    ],
+                ],
+                'errorHandling' => [],
+                'routes' => [],
+            ]
+        );
+
+        $subject = new MigrateSiteSettingsConfigUpdate();
+        $subject->executeUpdate();
+        self::assertFileDoesNotExist($this->getSettingsFilePath($siteconfigurationIdentifier));
+    }
+
+    protected function getSettingsFilePath(string $identifier): string
+    {
+        return Environment::getConfigPath() . '/sites/' . $identifier . '/settings.yaml';
+    }
+}
diff --git a/typo3/sysext/install/ext_localconf.php b/typo3/sysext/install/ext_localconf.php
index 7109819eb4974103f2165667f6abe462cf69a511..780249d30cf0e274fab6ac5ce6dc5ba0c86063fd 100644
--- a/typo3/sysext/install/ext_localconf.php
+++ b/typo3/sysext/install/ext_localconf.php
@@ -8,6 +8,7 @@ use TYPO3\CMS\Install\Updates\BackendUserLanguageMigration;
 use TYPO3\CMS\Install\Updates\CollectionsExtractionUpdate;
 use TYPO3\CMS\Install\Updates\DatabaseRowsUpdateWizard;
 use TYPO3\CMS\Install\Updates\FeLoginModeExtractionUpdate;
+use TYPO3\CMS\Install\Updates\MigrateSiteSettingsConfigUpdate;
 use TYPO3\CMS\Install\Updates\ShortcutRecordsMigration;
 use TYPO3\CMS\Install\Updates\SvgFilesSanitization;
 use TYPO3\CMS\Install\Updates\SysFileMountIdentifierMigration;
@@ -34,3 +35,4 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['backendGroup
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['sysFileMountIdentifierMigration'] = SysFileMountIdentifierMigration::class;
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['backendModulePermission'] = BackendModulePermissionMigration::class;
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['sysTemplateNoWorkspaceMigration'] = SysTemplateNoWorkspaceMigration::class;
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['migrateSiteSettings'] = MigrateSiteSettingsConfigUpdate::class;