diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 54759d9f5cc13e71f38a3867fb32f69dac429ae9..5e98e7db6d4609f5c48bcb9d4bef894a0bdfe88f 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -363,10 +363,14 @@ The "topic" is usually refers to the dependency being updated, e.g. `"dependency
 
 ## 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.
+By default, Renovate will ignore Composer platform requirements as the PHP platform used by Renovate most probably won't match the required PHP environment of your project as configured in your `composer.json` file.
 
-To solve this, you should configure explicit ignored platform requirements (for example `ext-zip`) by setting them separately in this array.
+Composer `2.2` and up will be run with `--ignore-platform-req='ext-*' --ignore-platform-req='lib-*'`, which ignores extension and library platform requirements but not the PHP version itself and should work in most cases.
+
+Older Composer versions will be run with `--ignore-platform-reqs`, which means that all platform constraints (including the PHP version) will be ignored by default.
+This can result in updated dependencies that are not compatible with your platform.
+
+To customize this behaviour, you can explicitly ignore 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.
 Note that this requires your project to use Composer V2, as V1 doesn't support excluding single platform requirements.
 The used PHP version will be guessed automatically from your `composer.json` definition, so `php` should not be added as explicit dependency.
diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts
index 78cfa37d0f294b7e727ec03dc6905de34fda909f..4e6c0c648906ab05599d44253099f159982609a6 100644
--- a/lib/manager/composer/artifacts.ts
+++ b/lib/manager/composer/artifacts.ts
@@ -125,7 +125,8 @@ export async function updateArtifacts({
     // Determine whether install is required before update
     if (requireComposerDependencyInstallation(existingLockFile)) {
       const preCmd = 'composer';
-      const preArgs = 'install' + getComposerArguments(config);
+      const preArgs =
+        'install' + getComposerArguments(config, composerToolConstraint);
       logger.debug({ preCmd, preArgs }, 'composer pre-update command');
       commands.push(`${preCmd} ${preArgs}`);
     }
@@ -140,7 +141,7 @@ export async function updateArtifacts({
           'update ' + updatedDeps.map((dep) => quote(dep.depName)).join(' ')
         ).trim() + ' --with-dependencies';
     }
-    args += getComposerArguments(config);
+    args += getComposerArguments(config, composerToolConstraint);
     logger.debug({ cmd, args }, 'composer command');
     commands.push(`${cmd} ${args}`);
 
diff --git a/lib/manager/composer/utils.spec.ts b/lib/manager/composer/utils.spec.ts
index 76b3efb091a187efcc9dd95b1aace1e063b332c2..563ff991fc239400b0e228b14ca6ac333b4b02a1 100644
--- a/lib/manager/composer/utils.spec.ts
+++ b/lib/manager/composer/utils.spec.ts
@@ -62,33 +62,80 @@ describe('manager/composer/utils', () => {
     });
 
     it('disables scripts and plugins by default', () => {
-      expect(getComposerArguments({})).toBe(
+      expect(
+        getComposerArguments({}, { toolName: 'composer', constraint: '1.*' })
+      ).toBe(
         ' --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins'
       );
     });
     it('disables platform requirements', () => {
       expect(
-        getComposerArguments({
-          composerIgnorePlatformReqs: [],
-        })
+        getComposerArguments(
+          {
+            composerIgnorePlatformReqs: [],
+          },
+          { toolName: 'composer', constraint: '1.*' }
+        )
+      ).toBe(
+        ' --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins'
+      );
+    });
+    it('disables all platform requirements with 2.1.0', () => {
+      expect(
+        getComposerArguments(
+          {
+            composerIgnorePlatformReqs: [],
+          },
+          { toolName: 'composer', constraint: '2.1.0' }
+        )
       ).toBe(
         ' --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins'
       );
     });
+    it('disables only extension and library platform requirements with 2.2.0', () => {
+      expect(
+        getComposerArguments(
+          {
+            composerIgnorePlatformReqs: [],
+          },
+          { toolName: 'composer', constraint: '2.2.0' }
+        )
+      ).toBe(
+        " --ignore-platform-req='ext-*' --ignore-platform-req='lib-*' --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins"
+      );
+    });
+    it('disables only extension and library platform requirements with ^2.2', () => {
+      expect(
+        getComposerArguments(
+          {
+            composerIgnorePlatformReqs: [],
+          },
+          { toolName: 'composer', constraint: '^2.2' }
+        )
+      ).toBe(
+        " --ignore-platform-req='ext-*' --ignore-platform-req='lib-*' --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins"
+      );
+    });
     it('disables single platform requirement', () => {
       expect(
-        getComposerArguments({
-          composerIgnorePlatformReqs: ['ext-intl'],
-        })
+        getComposerArguments(
+          {
+            composerIgnorePlatformReqs: ['ext-intl'],
+          },
+          { toolName: 'composer', constraint: '1.*' }
+        )
       ).toBe(
         ' --ignore-platform-req ext-intl --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins'
       );
     });
     it('disables multiple platform requirement', () => {
       expect(
-        getComposerArguments({
-          composerIgnorePlatformReqs: ['ext-intl', 'ext-icu'],
-        })
+        getComposerArguments(
+          {
+            composerIgnorePlatformReqs: ['ext-intl', 'ext-icu'],
+          },
+          { toolName: 'composer', constraint: '1.*' }
+        )
       ).toBe(
         ' --ignore-platform-req ext-intl --ignore-platform-req ext-icu --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins'
       );
@@ -97,18 +144,21 @@ describe('manager/composer/utils', () => {
       GlobalConfig.set({
         allowScripts: true,
       });
-      expect(getComposerArguments({})).toBe(
-        ' --no-ansi --no-interaction --no-plugins'
-      );
+      expect(
+        getComposerArguments({}, { toolName: 'composer', constraint: '1.*' })
+      ).toBe(' --no-ansi --no-interaction --no-plugins');
     });
     it('disables scripts when configured locally', () => {
       GlobalConfig.set({
         allowScripts: true,
       });
       expect(
-        getComposerArguments({
-          ignoreScripts: true,
-        })
+        getComposerArguments(
+          {
+            ignoreScripts: true,
+          },
+          { toolName: 'composer', constraint: '1.*' }
+        )
       ).toBe(
         ' --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins'
       );
@@ -117,18 +167,21 @@ describe('manager/composer/utils', () => {
       GlobalConfig.set({
         allowPlugins: true,
       });
-      expect(getComposerArguments({})).toBe(
-        ' --no-ansi --no-interaction --no-scripts --no-autoloader'
-      );
+      expect(
+        getComposerArguments({}, { toolName: 'composer', constraint: '1.*' })
+      ).toBe(' --no-ansi --no-interaction --no-scripts --no-autoloader');
     });
     it('disables plugins when configured locally', () => {
       GlobalConfig.set({
         allowPlugins: true,
       });
       expect(
-        getComposerArguments({
-          ignorePlugins: true,
-        })
+        getComposerArguments(
+          {
+            ignorePlugins: true,
+          },
+          { toolName: 'composer', constraint: '1.*' }
+        )
       ).toBe(
         ' --no-ansi --no-interaction --no-scripts --no-autoloader --no-plugins'
       );
diff --git a/lib/manager/composer/utils.ts b/lib/manager/composer/utils.ts
index 98f34bf2b451cd0f17eb15100fd38cb49069f815..d17fe86a9d3ffd1fdd1675b14f36b5ef894c7b5d 100644
--- a/lib/manager/composer/utils.ts
+++ b/lib/manager/composer/utils.ts
@@ -1,6 +1,7 @@
 import { quote } from 'shlex';
 import { GlobalConfig } from '../../config/global';
 import { logger } from '../../logger';
+import type { ToolConstraint } from '../../util/exec/types';
 import { api, id as composerVersioningId } from '../../versioning/composer';
 import type { UpdateArtifactsConfig } from '../types';
 import type { ComposerConfig, ComposerLock } from './types';
@@ -9,12 +10,19 @@ export { composerVersioningId };
 
 const depRequireInstall = new Set(['symfony/flex']);
 
-export function getComposerArguments(config: UpdateArtifactsConfig): string {
+export function getComposerArguments(
+  config: UpdateArtifactsConfig,
+  toolConstraint: ToolConstraint
+): string {
   let args = '';
 
   if (config.composerIgnorePlatformReqs) {
     if (config.composerIgnorePlatformReqs.length === 0) {
-      args += ' --ignore-platform-reqs';
+      const major = api.getMajor(toolConstraint.constraint);
+      const minor = api.getMinor(toolConstraint.constraint);
+      args += api.matches(`${major}.${minor}`, '^2.2')
+        ? " --ignore-platform-req='ext-*' --ignore-platform-req='lib-*'"
+        : ' --ignore-platform-reqs';
     } else {
       config.composerIgnorePlatformReqs.forEach((req) => {
         args += ' --ignore-platform-req ' + quote(req);