diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index e21b310b5d8f64b82c1de65ca071a30c7ab09001..d62cd96d5c15e2889fafcad9bd056ca618b466c1 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -14,6 +14,15 @@ const options = [
     allowString: true,
     cli: false,
   },
+  {
+    name: 'ignorePresets',
+    description:
+      'A list of presets to ignore, including nested ones inside `extends`',
+    stage: 'package',
+    type: 'list',
+    allowString: true,
+    cli: false,
+  },
   {
     name: 'description',
     description: 'Plain text description for a config or preset',
diff --git a/lib/config/presets.js b/lib/config/presets.js
index 1e6a98b7f280203bb09fac2c7fa9079377971f03..098d751c3d24157caf6be3272bec99f1a8f7416e 100644
--- a/lib/config/presets.js
+++ b/lib/config/presets.js
@@ -19,7 +19,14 @@ module.exports = {
   getPreset,
 };
 
-async function resolveConfigPresets(inputConfig, existingPresets = []) {
+async function resolveConfigPresets(
+  inputConfig,
+  ignorePresets,
+  existingPresets = []
+) {
+  if (!ignorePresets) {
+    ignorePresets = inputConfig.ignorePresets || []; // eslint-disable-line
+  }
   logger.trace(
     { config: inputConfig, existingPresets },
     'resolveConfigPresets'
@@ -31,6 +38,9 @@ async function resolveConfigPresets(inputConfig, existingPresets = []) {
       // istanbul ignore if
       if (existingPresets.includes(preset)) {
         logger.info(`Already seen preset ${preset} in ${existingPresets}`);
+      } else if (ignorePresets.includes(preset)) {
+        // istanbul ignore next
+        logger.info(`Ignoring preset ${preset} in ${existingPresets}`);
       } else {
         logger.trace(`Resolving preset "${preset}"`);
         let fetchedPreset;
@@ -61,6 +71,7 @@ async function resolveConfigPresets(inputConfig, existingPresets = []) {
         }
         const presetConfig = await resolveConfigPresets(
           fetchedPreset,
+          ignorePresets,
           existingPresets.concat([preset])
         );
         // istanbul ignore if
@@ -79,6 +90,7 @@ async function resolveConfigPresets(inputConfig, existingPresets = []) {
   // Now assign "regular" config on top
   config = configParser.mergeChildConfig(config, inputConfig);
   delete config.extends;
+  delete config.ignorePresets;
   logger.trace({ config }, `Post-merge resolve config`);
   for (const [key, val] of Object.entries(config)) {
     const ignoredKeys = ['content', 'onboardingConfig'];
@@ -88,7 +100,7 @@ async function resolveConfigPresets(inputConfig, existingPresets = []) {
       for (const element of val) {
         if (is.object(element)) {
           config[key].push(
-            await resolveConfigPresets(element, existingPresets)
+            await resolveConfigPresets(element, ignorePresets, existingPresets)
           );
         } else {
           config[key].push(element);
@@ -97,7 +109,11 @@ async function resolveConfigPresets(inputConfig, existingPresets = []) {
     } else if (is.object(val) && !ignoredKeys.includes(key)) {
       // Resolve nested objects
       logger.trace(`Resolving object "${key}"`);
-      config[key] = await resolveConfigPresets(val, existingPresets);
+      config[key] = await resolveConfigPresets(
+        val,
+        ignorePresets,
+        existingPresets
+      );
     }
   }
   logger.trace({ config: inputConfig }, 'Input config');
diff --git a/website/docs/configuration-options.md b/website/docs/configuration-options.md
index fc6a7bbbd4298fb02f8eba047e5d1d119e71a796..e723076aeb2c8da93d6fe9bd809353ee25756897 100644
--- a/website/docs/configuration-options.md
+++ b/website/docs/configuration-options.md
@@ -312,6 +312,19 @@ There may be times where an `.npmrc` file in your repository causes problems, su
 
 Using this setting, you can selectively ignore package files that you don't want Renovate autodiscovering. For instance if your repository has an "examples" directory of many package.json files that you don't want to be kept up to date.
 
+## ignorePresets
+
+Use this if you are extending a complex preset but won't want to use every "sub preset" that it uses. For example, take this config:
+
+```json
+{
+  "extends": ["config:base"],
+  "ignorePresets": [":prHourlyLimit2"]
+}
+```
+
+It would take the entire "config:base" preset - which contains a lot of sub-presets - but ignore the ":prHourlyLimit2" rule.
+
 ## ignoreUnstable
 
 By default, Renovate won't update any package versions to unstable versions (e.g. `4.0.0-rc3`) unless the current version has the same major.minor.patch and was _already_ unstable (e.g. it was already on `4.0.0-rc2`). Renovate will not "jump" unstable versions automatically, e.g. if you are on `4.0.0-rc2` and newer versions `4.0.0` and `4.1.0-alpha.1` exist then Renovate will update you to `4.0.0` only. If you need to force permanent unstable updates for a package, you can add a package rule setting `ignoreUnstable` to `false`.