diff --git a/lib/modules/datasource/docker/index.spec.ts b/lib/modules/datasource/docker/index.spec.ts
index 5049f640894baeba92b891d006ad029a4225cf54..48d38b1cca8f328cc6d99cf1d141be2f6bb45dd8 100644
--- a/lib/modules/datasource/docker/index.spec.ts
+++ b/lib/modules/datasource/docker/index.spec.ts
@@ -608,7 +608,7 @@ describe('modules/datasource/docker/index', () => {
         registryUrls: ['https://registry.company.com'],
       };
       const res = await getPkgReleases(config);
-      expect(res.releases).toHaveLength(1);
+      expect(res?.releases).toHaveLength(1);
     });
 
     it('uses custom registry in depName', async () => {
@@ -627,7 +627,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         depName: 'registry.company.com/node',
       });
-      expect(res.releases).toHaveLength(1);
+      expect(res?.releases).toHaveLength(1);
     });
 
     it('uses quay api', async () => {
@@ -652,7 +652,7 @@ describe('modules/datasource/docker/index', () => {
         registryUrls: ['https://quay.io'],
       };
       const res = await getPkgReleases(config);
-      expect(res.releases).toHaveLength(1);
+      expect(res?.releases).toHaveLength(1);
     });
 
     it('uses quay api and test error', async () => {
@@ -988,7 +988,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         depName: 'node',
       });
-      expect(res.releases).toHaveLength(1);
+      expect(res?.releases).toHaveLength(1);
     });
 
     it('adds library/ prefix for Docker Hub (explicit)', async () => {
@@ -1016,7 +1016,7 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         depName: 'docker.io/node',
       });
-      expect(res.releases).toHaveLength(1);
+      expect(res?.releases).toHaveLength(1);
     });
 
     it('adds no library/ prefix for other registries', async () => {
@@ -1042,14 +1042,14 @@ describe('modules/datasource/docker/index', () => {
         datasource: DockerDatasource.id,
         depName: 'k8s.gcr.io/kubernetes-dashboard-amd64',
       });
-      expect(res.releases).toHaveLength(1);
+      expect(res?.releases).toHaveLength(1);
     });
 
     it('returns null on error', async () => {
       httpMock
         .scope(baseUrl)
         .get('/my/node/tags/list?n=10000')
-        .reply(200, null)
+        .reply(200)
         .get('/my/node/tags/list?n=10000')
         .replyWithError('error');
       const res = await getPkgReleases({
@@ -1442,5 +1442,62 @@ describe('modules/datasource/docker/index', () => {
         releases: [],
       });
     });
+
+    it('supports ghcr', async () => {
+      hostRules.find.mockResolvedValue({} as never);
+      httpMock
+        .scope('https://ghcr.io/v2', {
+          badheaders: ['authorization'],
+        })
+        .get('/')
+        .twice()
+        .reply(401, '', {
+          'www-authenticate':
+            'Bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:user/image:pull',
+        })
+        .get('/visualon/drone-git/tags/list?n=10000')
+        .reply(401, '', {
+          'www-authenticate':
+            'Bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:visualon/drone-git:pull"',
+        });
+      httpMock
+        .scope('https://ghcr.io')
+        .get('/token?service=ghcr.io&scope=repository:visualon/drone-git:pull')
+        .times(3)
+        .reply(200, { token: 'abc' });
+      httpMock
+        .scope('https://ghcr.io/v2', {
+          reqheaders: {
+            authorization: 'Bearer abc',
+          },
+        })
+        .get('/visualon/drone-git/tags/list?n=10000')
+        .reply(200, { tags: ['latest', '1.0.0'] })
+        .get('/visualon/drone-git/manifests/latest')
+        .reply(200, {
+          schemaVersion: 2,
+          mediaType: MediaType.manifestV2,
+          config: { digest: 'some-config-digest' },
+        })
+        .get('/visualon/drone-git/blobs/some-config-digest')
+        .reply(200, {
+          config: {
+            Labels: {
+              'org.opencontainers.image.source':
+                'https://github.com/visualon/drone-git',
+            },
+          },
+        });
+
+      const res = await getPkgReleases({
+        datasource: DockerDatasource.id,
+        depName: 'ghcr.io/visualon/drone-git',
+      });
+      expect(res).toStrictEqual({
+        registryUrl: 'https://ghcr.io',
+        sourceUrl: 'https://github.com/visualon/drone-git',
+        releases: [{ version: '1.0.0' }],
+      });
+    });
   });
 });
diff --git a/lib/modules/datasource/docker/index.ts b/lib/modules/datasource/docker/index.ts
index 54e2e5fcae051cd98b92110465290b057ab18cdb..def48cc64fa71e746865e37393d8fad8d1b08219 100644
--- a/lib/modules/datasource/docker/index.ts
+++ b/lib/modules/datasource/docker/index.ts
@@ -136,7 +136,11 @@ export async function getAuthHeaders(
     }
 
     let scope = `repository:${dockerRepository}:pull`;
-    if (is.string(authenticateHeader.params.scope)) {
+    // repo isn't known to server yet, so causing wrong scope `repository:user/image:pull`
+    if (
+      is.string(authenticateHeader.params.scope) &&
+      !apiCheckUrl.endsWith('/v2/')
+    ) {
       scope = authenticateHeader.params.scope;
     }
 
diff --git a/test/http-mock.ts b/test/http-mock.ts
index f17942374f10c01dca858ac068d7b4f371c385d9..ded50e9e5b8237e62f2067612c0bfd5429765881 100644
--- a/test/http-mock.ts
+++ b/test/http-mock.ts
@@ -49,12 +49,12 @@ export function clear(throwOnPending = true): void {
   const missing = missingLog;
   requestLog = [];
   missingLog = [];
-  if (!isDone && throwOnPending) {
-    throw new Error(`Pending mocks!\n * ${pending.join('\n * ')}`);
-  }
   if (missing.length && throwOnPending) {
     throw new Error(`Missing mocks!\n * ${missing.join('\n * ')}`);
   }
+  if (!isDone && throwOnPending) {
+    throw new Error(`Pending mocks!\n * ${pending.join('\n * ')}`);
+  }
 }
 
 export function scope(basePath: BasePath, options?: nock.Options): nock.Scope {