diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 4b5cc2992b5e43ae7f3896dac5f115e9c5b4a234..c021f85fcafc6197ca2cff53eac58d53581c2d6a 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -357,6 +357,21 @@ Usually left empty except for internal use (multiple base branches, and vulnerab
 This is used to alter `commitMessage` and `prTitle` without needing to copy/paste the whole string.
 The "topic" is usually refers to the dependency being updated, e.g. `"dependency react"`.
 
+## composerIgnorePlatformReqs
+
+By default, Renovate will run Composer with `--ignore-platform-reqs` as the PHP platform used by Renovate most probably won't match with the required PHP environment of your project as configured in your `composer.json` file.
+However, this also means that all platform constraints (including PHP version) will be ignored by default, which can result in updated dependencies that are not compatible with your platform.
+
+To solve this, you should configure explicit ignored platform requirements (for example `ext-zip`) by setting them separately in this array.
+Each item will be added to the Composer command with `--ignore-platform-req`, resulting in it being ignored during its invocation.
+The used PHP version will be guessed automatically from your `composer.json` definition, so `php` should not be added as explicit dependency.
+
+If an empty array is configured, Renovate uses its default behaviour.
+
+Set to `null` (not recommended) to fully omit `--ignore-platform-reqs/--ignore-platform-req` during Composer invocation.
+This requires the Renovate image to be fully compatible with your Composer platform requirements in order for the Composer invocation to succeed, otherwise Renovate will fail to create the updated lock file.
+The Composer output should inform you about the reasons the update failed.
+
 ## configWarningReuseIssue
 
 Renovate's default behavior is to reuse/reopen a single Config Warning issue in each repository so as to keep the "noise" down.
diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md
index f48cbf777c22d96c3d1fe609e85ab4ab751d2772..5da83d57cbafe2e81896654d6ab6084f0b8e8f7c 100644
--- a/docs/usage/self-hosted-configuration.md
+++ b/docs/usage/self-hosted-configuration.md
@@ -126,10 +126,6 @@ e.g.
 }
 ```
 
-## composerIgnorePlatformReqs
-
-Set to `false` to prevent usage of `--ignore-platform-reqs` in the Composer package manager.s
-
 ## customEnvVariables
 
 This configuration will be applied after all other environment variables so that it can be used to override defaults.
diff --git a/lib/config/migration.spec.ts b/lib/config/migration.spec.ts
index 08bb570a5074e3265f353bd444f329af74f57e88..1fec9128db06dbfb0b59a5983c72ff92764c46b7 100644
--- a/lib/config/migration.spec.ts
+++ b/lib/config/migration.spec.ts
@@ -722,6 +722,33 @@ describe('config/migration', () => {
     expect(isMigrated).toBe(true);
     expect(migratedConfig).toEqual({ extends: ['local>org/renovate-config'] });
   });
+
+  it('it migrates composerIgnorePlatformReqs values', () => {
+    let config: TestRenovateConfig;
+    let res: MigratedConfig;
+
+    config = {
+      composerIgnorePlatformReqs: true,
+    } as never;
+    res = configMigration.migrateConfig(config);
+    expect(res.isMigrated).toBe(true);
+    expect(res.migratedConfig.composerIgnorePlatformReqs).toStrictEqual([]);
+
+    config = {
+      composerIgnorePlatformReqs: false,
+    } as never;
+    res = configMigration.migrateConfig(config);
+    expect(res.isMigrated).toBe(true);
+    expect(res.migratedConfig.composerIgnorePlatformReqs).toBeNull();
+
+    config = {
+      composerIgnorePlatformReqs: [],
+    } as never;
+    res = configMigration.migrateConfig(config);
+    expect(res.isMigrated).toBe(false);
+    expect(res.migratedConfig.composerIgnorePlatformReqs).toStrictEqual([]);
+  });
+
   it('it migrates gradle-lite', () => {
     const config: RenovateConfig = {
       gradle: {
diff --git a/lib/config/migration.ts b/lib/config/migration.ts
index d336a965b978e479fa64b42b33797e01e8205e3d..ef305caef7b100562a77baded14680f9a3e8f6cd 100644
--- a/lib/config/migration.ts
+++ b/lib/config/migration.ts
@@ -518,6 +518,12 @@ export function migrateConfig(
         }
       } else if (key === 'binarySource' && val === 'auto') {
         migratedConfig.binarySource = 'global';
+      } else if (key === 'composerIgnorePlatformReqs') {
+        if (val === true) {
+          migratedConfig.composerIgnorePlatformReqs = [];
+        } else if (val === false) {
+          migratedConfig.composerIgnorePlatformReqs = null;
+        }
       }
       const migratedTemplates = {
         fromVersion: 'currentVersion',
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index b796b0990ddd569b8401dc8914cc3f83b404cccf..1bacce70bfe644e0dfec816afd032fd5bd663cb3 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -298,10 +298,10 @@ const options: RenovateOptions[] = [
   {
     name: 'composerIgnorePlatformReqs',
     description:
-      'Enable / disable use of --ignore-platform-reqs in the Composer package manager.',
-    type: 'boolean',
-    default: true,
-    globalOnly: true,
+      'Configure use of `--ignore-platform-reqs`/`--ignore-platform-req` for the Composer package manager.',
+    type: 'array',
+    subType: 'string',
+    default: [],
   },
   // Log options
   {
diff --git a/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap b/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap
index f814fe495bea3dcaf3e3a3b181fe0bc96aa442ea..c9f2c54c08ee27320a85cff52e8fa36bd834fe78 100644
--- a/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap
+++ b/lib/manager/composer/__snapshots__/artifacts.spec.ts.snap
@@ -1,5 +1,29 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`manager/composer/artifacts adds all ignorePlatformReq items 1`] = `
+Array [
+  Object {
+    "cmd": "composer update --with-dependencies --ignore-platform-req ext-posix --ignore-platform-req ext-sodium --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins",
+    "options": Object {
+      "cwd": "/tmp/github/some/repo",
+      "encoding": "utf-8",
+      "env": Object {
+        "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer",
+        "HOME": "/home/user",
+        "HTTPS_PROXY": "https://example.com",
+        "HTTP_PROXY": "http://example.com",
+        "LANG": "en_US.UTF-8",
+        "LC_ALL": "en_US",
+        "NO_PROXY": "localhost",
+        "PATH": "/tmp/path",
+      },
+      "maxBuffer": 10485760,
+      "timeout": 900000,
+    },
+  },
+]
+`;
+
 exports[`manager/composer/artifacts catches errors 1`] = `
 Array [
   Object {
diff --git a/lib/manager/composer/artifacts.spec.ts b/lib/manager/composer/artifacts.spec.ts
index c382cc80c0d38de479caee7b19057d554c0d0901..c8d8f13b767c9a15c020c44742ab93a9537a7a1b 100644
--- a/lib/manager/composer/artifacts.spec.ts
+++ b/lib/manager/composer/artifacts.spec.ts
@@ -24,7 +24,7 @@ jest.mock('../../util/git');
 const datasource = mocked(_datasource);
 
 const config: UpdateArtifactsConfig = {
-  composerIgnorePlatformReqs: true,
+  composerIgnorePlatformReqs: [],
   ignoreScripts: false,
 };
 
@@ -337,7 +337,29 @@ describe('manager/composer/artifacts', () => {
         newPackageFileContent: '{}',
         config: {
           ...config,
-          composerIgnorePlatformReqs: false,
+          composerIgnorePlatformReqs: null,
+        },
+      })
+    ).not.toBeNull();
+    expect(execSnapshots).toMatchSnapshot();
+  });
+
+  it('adds all ignorePlatformReq items', async () => {
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    const execSnapshots = mockExecAll(exec);
+    fs.readLocalFile.mockResolvedValueOnce('{ }');
+    git.getRepoStatus.mockResolvedValue({
+      ...repoStatus,
+      modified: ['composer.lock'],
+    });
+    expect(
+      await composer.updateArtifacts({
+        packageFileName: 'composer.json',
+        updatedDeps: [],
+        newPackageFileContent: '{}',
+        config: {
+          ...config,
+          composerIgnorePlatformReqs: ['ext-posix', 'ext-sodium'],
         },
       })
     ).not.toBeNull();
diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts
index eb307b1a4e0b7f4d75a0694e525b882ae73ca700..17320ab16579fdb12f1063b3e57f0a8b49104cd1 100644
--- a/lib/manager/composer/artifacts.ts
+++ b/lib/manager/composer/artifacts.ts
@@ -134,7 +134,13 @@ export async function updateArtifacts({
         ).trim() + ' --with-dependencies';
     }
     if (config.composerIgnorePlatformReqs) {
-      args += ' --ignore-platform-reqs';
+      if (config.composerIgnorePlatformReqs.length === 0) {
+        args += ' --ignore-platform-reqs';
+      } else {
+        config.composerIgnorePlatformReqs.forEach((req) => {
+          args += ' --ignore-platform-req ' + quote(req);
+        });
+      }
     }
     args += ' --no-ansi --no-interaction';
     if (!getGlobalConfig().allowScripts || config.ignoreScripts) {
diff --git a/lib/manager/types.ts b/lib/manager/types.ts
index 000c830f0db307a00c5965eef2c5548c59ecb6a5..ef1ba6b9a7a4052228b076c2529d064a2ffa804b 100644
--- a/lib/manager/types.ts
+++ b/lib/manager/types.ts
@@ -41,7 +41,7 @@ export interface CustomExtractConfig extends ExtractConfig {
 export interface UpdateArtifactsConfig extends ManagerConfig {
   isLockFileMaintenance?: boolean;
   constraints?: Record<string, string>;
-  composerIgnorePlatformReqs?: boolean;
+  composerIgnorePlatformReqs?: string[];
   currentValue?: string;
   postUpdateOptions?: string[];
   ignoreScripts?: boolean;