diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 1fdb5949fd265334502c59f5ce128577f9218a09..78a95f31b08a24f102aeeeb776222e467d71c11a 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -1876,6 +1876,30 @@ For example to apply a special label for Major updates:
 }
 ```
 
+### customChangelogUrl
+
+Use this field to set the source URL for a package, including overriding an existing one.
+Source URLs are necessary in order to look up release notes.
+
+Using this field we can specify the exact url to fetch release notes from.
+
+Example setting source URL for package "dummy":
+
+```json
+{
+  "packageRules": [
+    {
+      "matchPackageNames": ["dummy"],
+      "customChangelogUrl": "https://github.com/org/dummy"
+    }
+  ]
+}
+```
+
+<!-- prettier-ignore -->
+!!! note
+Renovate can fetch changelogs from GitHub and GitLab platforms only, and setting the URL to an unsupported host/platform type won't change that.
+
 ### replacementName
 
 This config option only works with the `npm` manager.
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index a8736facccf5c49880169567c0b869cf301cd0ef..a744bc9dde4f192dbea6b09a66114b558d5c147f 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -1185,6 +1185,16 @@ const options: RenovateOptions[] = [
     cli: false,
     env: false,
   },
+  {
+    name: 'customChangelogUrl',
+    description:
+      'If set, Renovate will use this url to fetch changelogs for a matched dependency. Valid only within a `packageRules` object.',
+    type: 'string',
+    stage: 'pr',
+    parent: 'packageRules',
+    cli: false,
+    env: false,
+  },
   {
     name: 'pinDigests',
     description: 'Whether to add digests to Dockerfile source images.',
diff --git a/lib/config/types.ts b/lib/config/types.ts
index 65ccc58323e5c86e1cf4a789c90af6dcab27b121..a955ec2ee749b971f3dcce2ef7d37762e8d626c8 100644
--- a/lib/config/types.ts
+++ b/lib/config/types.ts
@@ -34,6 +34,7 @@ export interface RenovateSharedConfig {
   commitMessage?: string;
   commitMessagePrefix?: string;
   confidential?: boolean;
+  customChangelogUrl?: string;
   draftPR?: boolean;
   enabled?: boolean;
   enabledManagers?: string[];
diff --git a/lib/workers/repository/update/pr/changelog/common.spec.ts b/lib/workers/repository/update/pr/changelog/common.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ca4613d24c944262a14e5e106a17b8905ccceaae
--- /dev/null
+++ b/lib/workers/repository/update/pr/changelog/common.spec.ts
@@ -0,0 +1,14 @@
+import { slugifyUrl } from './common';
+
+describe('workers/repository/update/pr/changelog/common', () => {
+  it.each`
+    url                                                    | expected
+    ${'https://github-enterprise.example.com/çhãlk/chálk'} | ${'https-github-enterprise-example-com-chalk-chalk'}
+    ${'https://github.com/chalk/chalk'}                    | ${'https-github-com-chalk-chalk'}
+    ${'https://github-enterprise.example.com/'}            | ${'https-github-enterprise-example-com'}
+    ${'https://github.com/sindresorhus/delay'}             | ${'https-github-com-sindresorhus-delay'}
+    ${'https://github.com/🔥/∂u/∂t/equals/α∇^2u'}          | ${'https-github-com-du-dt-equals-a2u'}
+  `('isSingleVersion("$url") === $expected', ({ url, expected }) => {
+    expect(slugifyUrl(url)).toBe(expected);
+  });
+});
diff --git a/lib/workers/repository/update/pr/changelog/common.ts b/lib/workers/repository/update/pr/changelog/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cd2f8f4d3f90dcb46af97b7e5e69ec48325f60ed
--- /dev/null
+++ b/lib/workers/repository/update/pr/changelog/common.ts
@@ -0,0 +1,7 @@
+import slugify from 'slugify';
+import { regEx } from '../../../../../util/regex';
+
+export function slugifyUrl(url: string): string {
+  const r = regEx(/(:?[:/.])+/g);
+  return slugify(url.replace(r, ' '));
+}
diff --git a/lib/workers/repository/update/pr/changelog/github.spec.ts b/lib/workers/repository/update/pr/changelog/github.spec.ts
index cb5ab72dc5f11912cce3308496864d4ef871504b..7d0c6d6f2cbaf2fd8b96659d9067630ae7a40a4f 100644
--- a/lib/workers/repository/update/pr/changelog/github.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/github.spec.ts
@@ -265,6 +265,34 @@ describe('workers/repository/update/pr/changelog/github', () => {
       });
     });
 
+    it('supports overwriting sourceUrl for supports github enterprise and github.com changelog', async () => {
+      const sourceUrl = upgrade.sourceUrl;
+      const replacementSourceUrl = 'https://github.com/sindresorhus/got';
+      const config = {
+        ...upgrade,
+        endpoint: 'https://github-enterprise.example.com/',
+        customChangelogUrl: replacementSourceUrl,
+      };
+      hostRules.add({
+        hostType: PlatformId.Github,
+        token: 'super_secret',
+        matchHost: 'https://github-enterprise.example.com/',
+      });
+      expect(await getChangeLogJSON(config)).toMatchObject({
+        hasReleaseNotes: true,
+        project: {
+          apiBaseUrl: 'https://api.github.com/',
+          baseUrl: 'https://github.com/',
+          depName: 'renovate',
+          repository: 'sindresorhus/got',
+          sourceDirectory: undefined,
+          sourceUrl: 'https://github.com/sindresorhus/got',
+          type: 'github',
+        },
+      });
+      expect(upgrade.sourceUrl).toBe(sourceUrl); // ensure unmodified function argument
+    });
+
     it('supports github enterprise and github enterprise changelog', async () => {
       hostRules.add({
         hostType: PlatformId.Github,
@@ -298,6 +326,37 @@ describe('workers/repository/update/pr/changelog/github', () => {
       });
     });
 
+    it('supports overwriting sourceUrl for github enterprise and github enterprise changelog', async () => {
+      const sourceUrl = 'https://github-enterprise.example.com/chalk/chalk';
+      const replacementSourceUrl =
+        'https://github-enterprise.example.com/sindresorhus/got';
+      const config = {
+        ...upgrade,
+        sourceUrl,
+        endpoint: 'https://github-enterprise.example.com/',
+        customChangelogUrl: replacementSourceUrl,
+      };
+      hostRules.add({
+        hostType: PlatformId.Github,
+        matchHost: 'https://github-enterprise.example.com/',
+        token: 'abc',
+      });
+      process.env.GITHUB_ENDPOINT = '';
+      expect(await getChangeLogJSON(config)).toMatchObject({
+        hasReleaseNotes: true,
+        project: {
+          apiBaseUrl: 'https://github-enterprise.example.com/api/v3/',
+          baseUrl: 'https://github-enterprise.example.com/',
+          depName: 'renovate',
+          repository: 'sindresorhus/got',
+          sourceDirectory: undefined,
+          sourceUrl: 'https://github-enterprise.example.com/sindresorhus/got',
+          type: 'github',
+        },
+      });
+      expect(config.sourceUrl).toBe(sourceUrl); // ensure unmodified function argument
+    });
+
     it('works with same version releases but different prefix', async () => {
       const githubTagsMock = jest.spyOn(
         CacheableGithubTags.prototype,
diff --git a/lib/workers/repository/update/pr/changelog/gitlab.spec.ts b/lib/workers/repository/update/pr/changelog/gitlab.spec.ts
index 0e27e9f65115040e91c267035f334b42878af4c0..c9196a53e65697dbad799ea0b74d3e8c84b41b0f 100644
--- a/lib/workers/repository/update/pr/changelog/gitlab.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/gitlab.spec.ts
@@ -315,5 +315,38 @@ describe('workers/repository/update/pr/changelog/gitlab', () => {
         ],
       });
     });
+
+    it('supports overwriting sourceUrl for self-hosted gitlab changelog', async () => {
+      httpMock.scope('https://git.test.com').persist().get(/.*/).reply(200, []);
+      const sourceUrl = 'https://git.test.com/meno/dropzone/';
+      const replacementSourceUrl =
+        'https://git.test.com/replacement/sourceurl/';
+      const config = {
+        ...upgrade,
+        platform: PlatformId.Gitlab,
+        endpoint: 'https://git.test.com/api/v4/',
+        sourceUrl,
+        customChangelogUrl: replacementSourceUrl,
+      };
+      hostRules.add({
+        hostType: PlatformId.Gitlab,
+        matchHost: 'https://git.test.com/',
+        token: 'abc',
+      });
+      process.env.GITHUB_ENDPOINT = '';
+      expect(await getChangeLogJSON(config)).toMatchObject({
+        hasReleaseNotes: false,
+        project: {
+          apiBaseUrl: 'https://git.test.com/api/v4/',
+          baseUrl: 'https://git.test.com/',
+          depName: 'renovate',
+          repository: 'replacement/sourceurl',
+          sourceDirectory: undefined,
+          sourceUrl: 'https://git.test.com/replacement/sourceurl/',
+          type: 'gitlab',
+        },
+      });
+      expect(config.sourceUrl).toBe(sourceUrl); // ensure unmodified function argument
+    });
   });
 });
diff --git a/lib/workers/repository/update/pr/changelog/index.ts b/lib/workers/repository/update/pr/changelog/index.ts
index fcca0fc7f56028d078d1da1ae92874d34398587e..a0e07f0c22736d6df35a979536528f1fc0d53e51 100644
--- a/lib/workers/repository/update/pr/changelog/index.ts
+++ b/lib/workers/repository/update/pr/changelog/index.ts
@@ -9,9 +9,11 @@ import type { ChangeLogResult } from './types';
 export * from './types';
 
 export async function getChangeLogJSON(
-  config: BranchUpgradeConfig
+  _config: BranchUpgradeConfig
 ): Promise<ChangeLogResult | null> {
-  const { sourceUrl, versioning, currentVersion, newVersion } = config;
+  const sourceUrl = _config.customChangelogUrl ?? _config.sourceUrl!;
+  const config: BranchUpgradeConfig = { ..._config, sourceUrl };
+  const { versioning, currentVersion, newVersion } = config;
   try {
     if (!(sourceUrl && currentVersion && newVersion)) {
       return null;
diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts
index 7631f6cd2e90537f874e746bbdf8c63745427550..d8dabe224e50130aa7cf62278431294d5295cb32 100644
--- a/lib/workers/repository/update/pr/changelog/source-github.ts
+++ b/lib/workers/repository/update/pr/changelog/source-github.ts
@@ -10,6 +10,7 @@ import * as packageCache from '../../../../../util/cache/package';
 import * as hostRules from '../../../../../util/host-rules';
 import { regEx } from '../../../../../util/regex';
 import type { BranchUpgradeConfig } from '../../../../types';
+import { slugifyUrl } from './common';
 import { getTags } from './github';
 import { addReleaseNotes } from './release-notes';
 import { getInRangeReleases } from './releases';
@@ -120,8 +121,9 @@ export async function getChangeLogJSON(
   }
 
   const cacheNamespace = 'changelog-github-release';
+
   function getCacheKey(prev: string, next: string): string {
-    return `${manager}:${depName}:${prev}:${next}`;
+    return `${slugifyUrl(sourceUrl)}:${depName}:${prev}:${next}`;
   }
 
   const changelogReleases: ChangeLogRelease[] = [];
diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts
index 2cd1b38c2761090fed30a4c6dbd5f95bb1e02d26..e55b681849df16147d7271f314e9d04f5ff5560a 100644
--- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts
+++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts
@@ -7,6 +7,7 @@ import * as memCache from '../../../../../util/cache/memory';
 import * as packageCache from '../../../../../util/cache/package';
 import { regEx } from '../../../../../util/regex';
 import type { BranchUpgradeConfig } from '../../../../types';
+import { slugifyUrl } from './common';
 import { getTags } from './gitlab';
 import { addReleaseNotes } from './release-notes';
 import { getInRangeReleases } from './releases';
@@ -38,7 +39,6 @@ export async function getChangeLogJSON(
   const newVersion = config.newVersion!;
   const sourceUrl = config.sourceUrl!;
   const depName = config.depName!;
-  const manager = config.manager;
   const sourceDirectory = config.sourceDirectory!;
 
   logger.trace('getChangeLogJSON for gitlab');
@@ -95,7 +95,7 @@ export async function getChangeLogJSON(
   }
 
   function getCacheKey(prev: string, next: string): string {
-    return `${manager}:${depName}:${prev}:${next}`;
+    return `${slugifyUrl(sourceUrl)}:${depName}:${prev}:${next}`;
   }
 
   const changelogReleases: ChangeLogRelease[] = [];