diff --git a/docs/usage/config-validation.md b/docs/usage/config-validation.md
index 7871cc5367d072b2f7378779069c64b3058eff0a..88ee2cab3d03fa6b35fe6dd44cb2278b128f1d0b 100644
--- a/docs/usage/config-validation.md
+++ b/docs/usage/config-validation.md
@@ -18,5 +18,8 @@ INFO: Validating renovate.json
 INFO: Config validated successfully
 ```
 
+The validator program fails with a non-zero exit code if there are any validation warnings or errors.
+You can pass the `--strict` flag to make it fail if a scanned config needs migration.
+
 You can configure a [pre-commit](https://pre-commit.com) hook to validate your configuration automatically.
 Please check out the [`renovatebot/pre-commit-hooks` repository](https://github.com/renovatebot/pre-commit-hooks) for more information.
diff --git a/lib/config-validator.ts b/lib/config-validator.ts
index 07bf4bbe4cda03999a72e8b2d550e834607c8f0e..cccdb1a4f426b9a1e26cef37a5b9fb6a4ae59a4f 100644
--- a/lib/config-validator.ts
+++ b/lib/config-validator.ts
@@ -19,6 +19,7 @@ let returnVal = 0;
 async function validate(
   desc: string,
   config: RenovateConfig,
+  strict: boolean,
   isPreset = false
 ): Promise<void> {
   const { isMigrated, migratedConfig } = migrateConfig(config);
@@ -30,6 +31,9 @@ async function validate(
       },
       'Config migration necessary'
     );
+    if (strict) {
+      returnVal = 1;
+    }
   }
   const massagedConfig = massageConfig(migratedConfig);
   const res = await validateConfig(massagedConfig, isPreset);
@@ -55,6 +59,11 @@ type PackageJson = {
 };
 
 (async () => {
+  const strictArgIndex = process.argv.indexOf('--strict');
+  const strict = strictArgIndex >= 0;
+  if (strict) {
+    process.argv.splice(strictArgIndex);
+  }
   if (process.argv.length > 2) {
     for (const file of process.argv.slice(2)) {
       try {
@@ -66,7 +75,7 @@ type PackageJson = {
         const parsedContent = await getParsedContent(file);
         try {
           logger.info(`Validating ${file}`);
-          await validate(file, parsedContent);
+          await validate(file, parsedContent, strict);
         } catch (err) {
           logger.warn({ file, err }, 'File is not valid Renovate config');
           returnVal = 1;
@@ -87,7 +96,7 @@ type PackageJson = {
         const parsedContent = await getParsedContent(file);
         try {
           logger.info(`Validating ${file}`);
-          await validate(file, parsedContent);
+          await validate(file, parsedContent, strict);
         } catch (err) {
           logger.warn({ file, err }, 'File is not valid Renovate config');
           returnVal = 1;
@@ -103,12 +112,17 @@ type PackageJson = {
       ) as PackageJson;
       if (pkgJson.renovate) {
         logger.info(`Validating package.json > renovate`);
-        await validate('package.json > renovate', pkgJson.renovate);
+        await validate('package.json > renovate', pkgJson.renovate, strict);
       }
       if (pkgJson['renovate-config']) {
         logger.info(`Validating package.json > renovate-config`);
         for (const presetConfig of Object.values(pkgJson['renovate-config'])) {
-          await validate('package.json > renovate-config', presetConfig, true);
+          await validate(
+            'package.json > renovate-config',
+            presetConfig,
+            strict,
+            true
+          );
         }
       }
     } catch (err) {
@@ -120,7 +134,7 @@ type PackageJson = {
         const file = process.env.RENOVATE_CONFIG_FILE ?? 'config.js';
         logger.info(`Validating ${file}`);
         try {
-          await validate(file, fileConfig);
+          await validate(file, fileConfig, strict);
         } catch (err) {
           logger.error({ file, err }, 'File is not valid Renovate config');
           returnVal = 1;