diff --git a/docs/usage/self-hosted-experimental.md b/docs/usage/self-hosted-experimental.md
index 5945938bef3cbf47a19714e338e515914dd618bc..47fd66b1cfd0be17e7d4eca83ab48c47a25b0dda 100644
--- a/docs/usage/self-hosted-experimental.md
+++ b/docs/usage/self-hosted-experimental.md
@@ -71,6 +71,13 @@ Source: [AWS S3 documentation - Interface BucketEndpointInputConfig](https://doc
 
 If set, Renovate will terminate the whole process group of a terminated child process spawned by Renovate.
 
+## `RENOVATE_X_DELETE_CONFIG_FILE`
+
+If `true` Renovate tries to delete the self-hosted config file after reading it.
+You can set the config file Renovate should read with the `RENOVATE_CONFIG_FILE` environment variable.
+
+The process that runs Renovate must have the correct permissions to delete the config file.
+
 ## `RENOVATE_X_MATCH_PACKAGE_NAMES_MORE`
 
 If set, you'll get the following behavior.
diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts
index 6dd841bd6eec7fcb8e43b8925b90b7d4b137135b..e0aaf92406a91ec872a535a0a96497d032f53b8a 100644
--- a/lib/workers/global/config/parse/file.spec.ts
+++ b/lib/workers/global/config/parse/file.spec.ts
@@ -7,6 +7,10 @@ import customConfig from './__fixtures__/config';
 import * as file from './file';
 
 describe('workers/global/config/parse/file', () => {
+  const processExitSpy = jest.spyOn(process, 'exit');
+  const fsPathExistsSpy = jest.spyOn(fsExtra, 'pathExists');
+  const fsRemoveSpy = jest.spyOn(fsExtra, 'remove');
+
   let tmp: DirectoryResult;
 
   beforeAll(async () => {
@@ -71,32 +75,28 @@ describe('workers/global/config/parse/file', () => {
     ])(
       'fatal error and exit if error in parsing %s',
       async (fileName, fileContent) => {
-        const mockProcessExit = jest
-          .spyOn(process, 'exit')
-          .mockImplementationOnce(() => undefined as never);
+        processExitSpy.mockImplementationOnce(() => undefined as never);
         const configFile = upath.resolve(tmp.path, fileName);
         fs.writeFileSync(configFile, fileContent, { encoding: 'utf8' });
         await file.getConfig({ RENOVATE_CONFIG_FILE: configFile });
-        expect(mockProcessExit).toHaveBeenCalledWith(1);
+        expect(processExitSpy).toHaveBeenCalledWith(1);
         fs.unlinkSync(configFile);
       }
     );
 
     it('fatal error and exit if custom config file does not exist', async () => {
-      const mockProcessExit = jest
-        .spyOn(process, 'exit')
-        .mockImplementation(() => undefined as never);
-
+      processExitSpy
+        .mockImplementationOnce(() => undefined as never)
+        .mockImplementationOnce(() => undefined as never);
       const configFile = upath.resolve(tmp.path, './file4.js');
+
       await file.getConfig({ RENOVATE_CONFIG_FILE: configFile });
 
-      expect(mockProcessExit).toHaveBeenCalledWith(1);
+      expect(processExitSpy).toHaveBeenCalledWith(1);
     });
 
     it('fatal error and exit if config.js contains unresolved env var', async () => {
-      const mockProcessExit = jest
-        .spyOn(process, 'exit')
-        .mockImplementation(() => undefined as never);
+      processExitSpy.mockImplementationOnce(() => undefined as never);
 
       const configFile = upath.resolve(
         __dirname,
@@ -113,22 +113,115 @@ describe('workers/global/config/parse/file', () => {
       expect(logger.fatal).toHaveBeenCalledWith(
         `Error parsing config file due to unresolved variable(s): CI_API_V4_URL is not defined`
       );
-      expect(mockProcessExit).toHaveBeenCalledWith(1);
+      expect(processExitSpy).toHaveBeenCalledWith(1);
     });
 
     it.each([
       ['invalid config file type', './file.txt'],
       ['missing config file type', './file'],
     ])('fatal error and exit if %s', async (fileType, filePath) => {
-      const mockProcessExit = jest
-        .spyOn(process, 'exit')
-        .mockImplementationOnce(() => undefined as never);
+      processExitSpy.mockImplementationOnce(() => undefined as never);
       const configFile = upath.resolve(tmp.path, filePath);
       fs.writeFileSync(configFile, `{"token": "abc"}`, { encoding: 'utf8' });
       await file.getConfig({ RENOVATE_CONFIG_FILE: configFile });
-      expect(mockProcessExit).toHaveBeenCalledWith(1);
+      expect(processExitSpy).toHaveBeenCalledWith(1);
       expect(logger.fatal).toHaveBeenCalledWith('Unsupported file type');
       fs.unlinkSync(configFile);
     });
+
+    it('removes the config file if RENOVATE_CONFIG_FILE & RENOVATE_X_DELETE_CONFIG_FILE are set', async () => {
+      fsRemoveSpy.mockImplementationOnce(() => {
+        // no-op
+      });
+      fsPathExistsSpy.mockResolvedValueOnce(true as never);
+      const configFile = upath.resolve(tmp.path, './config.json');
+      fs.writeFileSync(configFile, `{"token": "abc"}`, { encoding: 'utf8' });
+
+      await file.getConfig({
+        RENOVATE_CONFIG_FILE: configFile,
+        RENOVATE_X_DELETE_CONFIG_FILE: 'true',
+      });
+
+      expect(processExitSpy).not.toHaveBeenCalled();
+      expect(fsRemoveSpy).toHaveBeenCalledTimes(1);
+      expect(fsRemoveSpy).toHaveBeenCalledWith(configFile);
+      fs.unlinkSync(configFile);
+    });
+  });
+
+  describe('deleteConfigFile()', () => {
+    it.each([[undefined], [' ']])(
+      'skip when RENOVATE_CONFIG_FILE is not set ("%s")',
+      async (configFile) => {
+        await file.deleteNonDefaultConfig({ RENOVATE_CONFIG_FILE: configFile });
+
+        expect(fsRemoveSpy).toHaveBeenCalledTimes(0);
+      }
+    );
+
+    it('skip when config file does not exist', async () => {
+      fsPathExistsSpy.mockResolvedValueOnce(false as never);
+
+      await file.deleteNonDefaultConfig({
+        RENOVATE_CONFIG_FILE: 'path',
+        RENOVATE_X_DELETE_CONFIG_FILE: 'true',
+      });
+
+      expect(fsRemoveSpy).toHaveBeenCalledTimes(0);
+    });
+
+    it.each([['false'], [' ']])(
+      'skip if RENOVATE_X_DELETE_CONFIG_FILE is not set ("%s")',
+      async (deleteConfig) => {
+        fsPathExistsSpy.mockResolvedValueOnce(true as never);
+
+        await file.deleteNonDefaultConfig({
+          RENOVATE_X_DELETE_CONFIG_FILE: deleteConfig,
+          RENOVATE_CONFIG_FILE: '/path/to/config.js',
+        });
+
+        expect(fsRemoveSpy).toHaveBeenCalledTimes(0);
+      }
+    );
+
+    it('removes the specified config file', async () => {
+      fsRemoveSpy.mockImplementationOnce(() => {
+        // no-op
+      });
+      fsPathExistsSpy.mockResolvedValueOnce(true as never);
+      const configFile = '/path/to/config.js';
+
+      await file.deleteNonDefaultConfig({
+        RENOVATE_CONFIG_FILE: configFile,
+        RENOVATE_X_DELETE_CONFIG_FILE: 'true',
+      });
+
+      expect(fsRemoveSpy).toHaveBeenCalledTimes(1);
+      expect(fsRemoveSpy).toHaveBeenCalledWith(configFile);
+      expect(logger.trace).toHaveBeenCalledWith(
+        expect.anything(),
+        'config file successfully deleted'
+      );
+    });
+
+    it('fails silently when attempting to delete the config file', async () => {
+      fsRemoveSpy.mockImplementationOnce(() => {
+        throw new Error();
+      });
+      fsPathExistsSpy.mockResolvedValueOnce(true as never);
+      const configFile = '/path/to/config.js';
+
+      await file.deleteNonDefaultConfig({
+        RENOVATE_CONFIG_FILE: configFile,
+        RENOVATE_X_DELETE_CONFIG_FILE: 'true',
+      });
+
+      expect(fsRemoveSpy).toHaveBeenCalledTimes(1);
+      expect(fsRemoveSpy).toHaveBeenCalledWith(configFile);
+      expect(logger.warn).toHaveBeenCalledWith(
+        expect.anything(),
+        'error deleting config file'
+      );
+    });
   });
 });
diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts
index 871fe10f457cea0aa8a5f6d3a0ef5fb77ab5ca9e..ba255ecd10d79492ce40eced41c1746bffea3005 100644
--- a/lib/workers/global/config/parse/file.ts
+++ b/lib/workers/global/config/parse/file.ts
@@ -71,6 +71,9 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise<AllConfig> {
       logger.debug('No config file found on disk - skipping');
     }
   }
+
+  await deleteNonDefaultConfig(env); // Attempt deletion only if RENOVATE_CONFIG_FILE is specified
+
   const { isMigrated, migratedConfig } = migrateConfig(config);
   if (isMigrated) {
     logger.warn(
@@ -81,3 +84,28 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise<AllConfig> {
   }
   return config;
 }
+
+export async function deleteNonDefaultConfig(
+  env: NodeJS.ProcessEnv
+): Promise<void> {
+  const configFile = env.RENOVATE_CONFIG_FILE;
+
+  if (is.undefined(configFile) || is.emptyStringOrWhitespace(configFile)) {
+    return;
+  }
+
+  if (env.RENOVATE_X_DELETE_CONFIG_FILE !== 'true') {
+    return;
+  }
+
+  if (!(await fs.pathExists(configFile))) {
+    return;
+  }
+
+  try {
+    await fs.remove(configFile);
+    logger.trace({ path: configFile }, 'config file successfully deleted');
+  } catch (err) {
+    logger.warn({ err }, 'error deleting config file');
+  }
+}