diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 84b388f31ffe9639eabe23ea7b3e362b6000a8e5..903ca5354af5b421dafefa28465f0b5e0ed22553 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -441,6 +441,11 @@ You can configure this to `true` if you prefer Renovate to close an existing Dep
 
 ## dependencyDashboardHeader
 
+## dependencyDashboardLabels
+
+The labels only get updated when the Dependency Dashboard issue updates its content and/or title.
+It is pointless to edit the labels, as Renovate bot restores the labels on each run.
+
 ## dependencyDashboardTitle
 
 Configure this option if you prefer a different title for the Dependency Dashboard.
diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts
index b59c9ae23f22fe5a69cc1699db4f0f0f5e837aac..5fd76556985d31f12ebc14f09dbf153d8bc1f498 100644
--- a/lib/config/definitions.ts
+++ b/lib/config/definitions.ts
@@ -419,6 +419,13 @@ const options: RenovateOptions[] = [
       'Any text added here will be placed last in the Dependency Dashboard issue body, with a divider separator before it.',
     type: 'string',
   },
+  {
+    name: 'dependencyDashboardLabels',
+    description:
+      'These labels will always be applied on the Dependency Dashboard issue, even when they have been removed manually.',
+    type: 'array',
+    subType: 'string',
+  },
   {
     name: 'configWarningReuseIssue',
     description:
diff --git a/lib/config/types.ts b/lib/config/types.ts
index 1e99efe1ba410842d6dd0f2759afb6476e5fdaca..3fa1a645c2a7c7125b0ace70110022546993cc67 100644
--- a/lib/config/types.ts
+++ b/lib/config/types.ts
@@ -182,6 +182,7 @@ export interface RenovateConfig
   dependencyDashboardTitle?: string;
   dependencyDashboardHeader?: string;
   dependencyDashboardFooter?: string;
+  dependencyDashboardLabels?: string[];
   packageFile?: string;
   packageRules?: PackageRule[];
   postUpdateOptions?: string[];
diff --git a/lib/platform/gitea/__snapshots__/gitea-helper.spec.ts.snap b/lib/platform/gitea/__snapshots__/gitea-helper.spec.ts.snap
index 5be3dfd1533198c8042f0bbb074bbf63b45f5173..2d4ed35815b745add455edd6175810156878b928 100644
--- a/lib/platform/gitea/__snapshots__/gitea-helper.spec.ts.snap
+++ b/lib/platform/gitea/__snapshots__/gitea-helper.spec.ts.snap
@@ -765,6 +765,24 @@ Array [
 ]
 `;
 
+exports[`platform/gitea/gitea-helper updateIssueLabels should call /api/v1/repos/[repo]/issues/[issue]/labels endpoint 1`] = `
+Array [
+  Object {
+    "body": "{\\"labels\\":[1,3]}",
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate, br",
+      "content-length": "16",
+      "content-type": "application/json",
+      "host": "gitea.renovatebot.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "PUT",
+    "url": "https://gitea.renovatebot.com/api/v1/repos/some/repo/issues/7/labels",
+  },
+]
+`;
+
 exports[`platform/gitea/gitea-helper updatePR should call /api/v1/repos/[repo]/pulls/[pull] endpoint 1`] = `
 Array [
   Object {
diff --git a/lib/platform/gitea/gitea-helper.spec.ts b/lib/platform/gitea/gitea-helper.spec.ts
index 4095b539dc8004931ecf8018008351ce0ca66195..4d1ea8a3e905101ffb887d36755c5e3ea988095e 100644
--- a/lib/platform/gitea/gitea-helper.spec.ts
+++ b/lib/platform/gitea/gitea-helper.spec.ts
@@ -85,6 +85,7 @@ describe(getName(), () => {
     title: 'Some Issue',
     body: 'just some issue',
     assignees: [mockUser],
+    labels: [],
   };
 
   const mockComment: ght.Comment = {
@@ -469,6 +470,30 @@ describe(getName(), () => {
     });
   });
 
+  describe('updateIssueLabels', () => {
+    it('should call /api/v1/repos/[repo]/issues/[issue]/labels endpoint', async () => {
+      const updatedMockLabels: Partial<ght.Label>[] = [
+        { id: 1, name: 'Renovate' },
+        { id: 3, name: 'Maintenance' },
+      ];
+
+      httpMock
+        .scope(baseUrl)
+        .put(`/repos/${mockRepo.full_name}/issues/${mockIssue.number}/labels`)
+        .reply(200, updatedMockLabels);
+
+      const res = await ght.updateIssueLabels(
+        mockRepo.full_name,
+        mockIssue.number,
+        {
+          labels: [1, 3],
+        }
+      );
+      expect(res).toEqual(updatedMockLabels);
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
+  });
+
   describe('closeIssue', () => {
     it('should call /api/v1/repos/[repo]/issues/[issue] endpoint', async () => {
       httpMock
diff --git a/lib/platform/gitea/gitea-helper.ts b/lib/platform/gitea/gitea-helper.ts
index 88e2bec406546311add2b229f6c36a3e2cbd9215..2e9a3af680f742800c1deec6edc8ceafa8865bfd 100644
--- a/lib/platform/gitea/gitea-helper.ts
+++ b/lib/platform/gitea/gitea-helper.ts
@@ -46,6 +46,7 @@ export interface Issue {
   title: string;
   body: string;
   assignees: User[];
+  labels: Label[];
 }
 
 export interface User {
@@ -135,7 +136,8 @@ export type RepoSearchParams = {
   archived?: boolean;
 };
 
-export type IssueCreateParams = IssueUpdateParams;
+export type IssueCreateParams = Partial<IssueUpdateLabelsParams> &
+  IssueUpdateParams;
 
 export type IssueUpdateParams = {
   title?: string;
@@ -144,6 +146,10 @@ export type IssueUpdateParams = {
   assignees?: string[];
 };
 
+export type IssueUpdateLabelsParams = {
+  labels: number[];
+};
+
 export type IssueSearchParams = {
   state?: IssueState;
 };
@@ -374,6 +380,21 @@ export async function updateIssue(
   return res.body;
 }
 
+export async function updateIssueLabels(
+  repoPath: string,
+  idx: number,
+  params: IssueUpdateLabelsParams,
+  options?: GiteaHttpOptions
+): Promise<Label[]> {
+  const url = `repos/${repoPath}/issues/${idx}/labels`;
+  const res = await giteaHttp.putJson<Label[]>(url, {
+    ...options,
+    body: params,
+  });
+
+  return res.body;
+}
+
 export async function closeIssue(
   repoPath: string,
   idx: number,
diff --git a/lib/platform/gitea/index.spec.ts b/lib/platform/gitea/index.spec.ts
index d5ab8c01d8dcd1ca2cfb1af2ffe2a00650250f6f..6a0ade67ca10f40b3d994ef1b05bf4ea60ac58cf 100644
--- a/lib/platform/gitea/index.spec.ts
+++ b/lib/platform/gitea/index.spec.ts
@@ -1,4 +1,10 @@
-import { BranchStatusConfig, Platform, RepoParams, RepoResult } from '..';
+import {
+  BranchStatusConfig,
+  EnsureIssueConfig,
+  Platform,
+  RepoParams,
+  RepoResult,
+} from '..';
 import { getName, partial } from '../../../test/util';
 import {
   REPOSITORY_ACCESS_FORBIDDEN,
@@ -94,6 +100,7 @@ describe(getName(), () => {
       state: 'open',
       body: 'some-content',
       assignees: [],
+      labels: [],
     },
     {
       number: 2,
@@ -101,6 +108,7 @@ describe(getName(), () => {
       state: 'closed',
       body: 'other-content',
       assignees: [],
+      labels: [],
     },
     {
       number: 3,
@@ -108,6 +116,7 @@ describe(getName(), () => {
       state: 'open',
       body: 'duplicate-content',
       assignees: [],
+      labels: [],
     },
     {
       number: 4,
@@ -115,6 +124,7 @@ describe(getName(), () => {
       state: 'open',
       body: 'duplicate-content',
       assignees: [],
+      labels: [],
     },
     {
       number: 5,
@@ -122,6 +132,7 @@ describe(getName(), () => {
       state: 'open',
       body: 'duplicate-content',
       assignees: [],
+      labels: [],
     },
   ];
 
@@ -972,9 +983,43 @@ describe(getName(), () => {
       });
     });
 
+    it('should create issue with the correct labels', async () => {
+      const mockIssue: EnsureIssueConfig = {
+        title: 'new-title',
+        body: 'new-body',
+        shouldReOpen: false,
+        once: false,
+        labels: ['Renovate', 'Maintenance'],
+      };
+      const mockLabels: ght.Label[] = [
+        partial<ght.Label>({ id: 1, name: 'Renovate' }),
+        partial<ght.Label>({ id: 3, name: 'Maintenance' }),
+      ];
+
+      helper.getRepoLabels.mockResolvedValueOnce(partial(mockLabels));
+      helper.getOrgLabels.mockResolvedValueOnce([]);
+
+      helper.searchIssues.mockResolvedValueOnce(mockIssues);
+      helper.createIssue.mockResolvedValueOnce(
+        partial<ght.Issue>({ number: 42 })
+      );
+
+      await initFakeRepo();
+      const res = await gitea.ensureIssue(mockIssue);
+
+      expect(res).toEqual('created');
+      expect(helper.createIssue).toHaveBeenCalledTimes(1);
+      expect(helper.createIssue).toHaveBeenCalledWith(mockRepo.full_name, {
+        body: mockIssue.body,
+        title: mockIssue.title,
+        labels: [1, 3],
+      });
+    });
+
     it('should not reopen closed issue by default', async () => {
       const closedIssue = mockIssues.find((i) => i.title === 'closed-issue');
       helper.searchIssues.mockResolvedValueOnce(mockIssues);
+      helper.updateIssue.mockResolvedValueOnce(closedIssue);
 
       await initFakeRepo();
       const res = await gitea.ensureIssue({
@@ -997,9 +1042,118 @@ describe(getName(), () => {
       );
     });
 
+    it('should not update labels when not necessary', async () => {
+      const mockLabels: ght.Label[] = [
+        partial<ght.Label>({ id: 1, name: 'Renovate' }),
+        partial<ght.Label>({ id: 3, name: 'Maintenance' }),
+      ];
+      const mockIssue: ght.Issue = {
+        number: 10,
+        title: 'label-issue',
+        body: 'label-body',
+        assignees: [],
+        labels: mockLabels,
+        state: 'open',
+      };
+
+      helper.getRepoLabels.mockResolvedValueOnce(partial(mockLabels));
+      helper.getOrgLabels.mockResolvedValueOnce([]);
+      helper.searchIssues.mockResolvedValueOnce([mockIssue]);
+      helper.updateIssue.mockResolvedValueOnce(mockIssue);
+
+      await initFakeRepo();
+      const res = await gitea.ensureIssue({
+        title: mockIssue.title,
+        body: 'new-body',
+        labels: ['Renovate', 'Maintenance'],
+      });
+
+      expect(res).toEqual('updated');
+      expect(helper.updateIssue).toHaveBeenCalledTimes(1);
+      expect(helper.updateIssueLabels).toHaveBeenCalledTimes(0);
+    });
+
+    it('should update labels when missing', async () => {
+      const mockLabels: ght.Label[] = [
+        partial<ght.Label>({ id: 1, name: 'Renovate' }),
+        partial<ght.Label>({ id: 3, name: 'Maintenance' }),
+      ];
+      const mockIssue: ght.Issue = {
+        number: 10,
+        title: 'label-issue',
+        body: 'label-body',
+        assignees: [],
+        labels: [mockLabels[0]],
+        state: 'open',
+      };
+
+      helper.getRepoLabels.mockResolvedValueOnce(partial(mockLabels));
+      helper.getOrgLabels.mockResolvedValueOnce([]);
+      helper.searchIssues.mockResolvedValueOnce([mockIssue]);
+      helper.updateIssue.mockResolvedValueOnce(mockIssue);
+
+      await initFakeRepo();
+      const res = await gitea.ensureIssue({
+        title: mockIssue.title,
+        body: 'new-body',
+        labels: ['Renovate', 'Maintenance'],
+      });
+
+      expect(res).toEqual('updated');
+      expect(helper.updateIssue).toHaveBeenCalledTimes(1);
+      expect(helper.updateIssueLabels).toHaveBeenCalledTimes(1);
+      expect(helper.updateIssueLabels).toHaveBeenCalledWith(
+        mockRepo.full_name,
+        mockIssue.number,
+        {
+          labels: [1, 3],
+        }
+      );
+    });
+
+    it('should reset labels when others have been set', async () => {
+      const mockLabels: ght.Label[] = [
+        partial<ght.Label>({ id: 1, name: 'Renovate' }),
+        partial<ght.Label>({ id: 2, name: 'Other label' }),
+        partial<ght.Label>({ id: 3, name: 'Maintenance' }),
+      ];
+      const mockIssue: ght.Issue = {
+        number: 10,
+        title: 'label-issue',
+        body: 'label-body',
+        assignees: [],
+        labels: mockLabels,
+        state: 'open',
+      };
+
+      helper.getRepoLabels.mockResolvedValueOnce(partial(mockLabels));
+      helper.getOrgLabels.mockResolvedValueOnce([]);
+      helper.searchIssues.mockResolvedValueOnce([mockIssue]);
+      helper.updateIssue.mockResolvedValueOnce(mockIssue);
+
+      await initFakeRepo();
+      const res = await gitea.ensureIssue({
+        title: mockIssue.title,
+        body: 'new-body',
+        labels: ['Renovate', 'Maintenance'],
+      });
+
+      expect(res).toEqual('updated');
+      expect(helper.updateIssue).toHaveBeenCalledTimes(1);
+      expect(helper.updateIssueLabels).toHaveBeenCalledTimes(1);
+      expect(helper.updateIssueLabels).toHaveBeenCalledWith(
+        mockRepo.full_name,
+        mockIssue.number,
+        {
+          labels: [1, 3],
+        }
+      );
+    });
+
     it('should reopen closed issue if desired', async () => {
       const closedIssue = mockIssues.find((i) => i.title === 'closed-issue');
       helper.searchIssues.mockResolvedValueOnce(mockIssues);
+      helper.updateIssue.mockResolvedValueOnce(closedIssue);
 
       await initFakeRepo();
       const res = await gitea.ensureIssue({
diff --git a/lib/platform/gitea/index.ts b/lib/platform/gitea/index.ts
index 0458ff5758f7fe17a94c68a52e0eca3b2ddac9ee..61aca917500fd9da4631bbbd32b569201e24191d 100644
--- a/lib/platform/gitea/index.ts
+++ b/lib/platform/gitea/index.ts
@@ -621,6 +621,7 @@ const platform: Platform = {
     title,
     reuseTitle,
     body: content,
+    labels: labelNames,
     shouldReOpen,
     once,
   }: EnsureIssueConfig): Promise<'updated' | 'created' | null> {
@@ -633,6 +634,11 @@ const platform: Platform = {
       if (!issues.length) {
         issues = issueList.filter((i) => i.title === reuseTitle);
       }
+
+      const labels = Array.isArray(labelNames)
+        ? await Promise.all(labelNames.map(lookupLabelByName))
+        : undefined;
+
       // Update any matching issues which currently exist
       if (issues.length) {
         let activeIssue = issues.find((i) => i.state === 'open');
@@ -673,13 +679,37 @@ const platform: Platform = {
 
         // Update issue body and re-open if enabled
         logger.debug(`Updating Issue #${activeIssue.number}`);
-        await helper.updateIssue(config.repository, activeIssue.number, {
-          body,
-          title,
-          state: shouldReOpen
-            ? 'open'
-            : (activeIssue.state as helper.IssueState),
-        });
+        const existingIssue = await helper.updateIssue(
+          config.repository,
+          activeIssue.number,
+          {
+            body,
+            title,
+            state: shouldReOpen
+              ? 'open'
+              : (activeIssue.state as helper.IssueState),
+          }
+        );
+
+        // Test whether the issues need to be updated
+        const existingLabelIds = (existingIssue.labels ?? []).map(
+          (label) => label.id
+        );
+        if (
+          labels !== undefined &&
+          labels.length !== 0 &&
+          (labels.length !== existingLabelIds.length ||
+            labels.filter((labelId) => !existingLabelIds.includes(labelId))
+              .length !== 0)
+        ) {
+          await helper.updateIssueLabels(
+            config.repository,
+            activeIssue.number,
+            {
+              labels,
+            }
+          );
+        }
 
         return 'updated';
       }
@@ -688,6 +718,7 @@ const platform: Platform = {
       const issue = await helper.createIssue(config.repository, {
         body,
         title,
+        labels,
       });
       logger.debug(`Created new Issue #${issue.number}`);
       config.issueList = null;
diff --git a/lib/platform/github/__snapshots__/index.spec.ts.snap b/lib/platform/github/__snapshots__/index.spec.ts.snap
index f1ea6d0f2b77a6c54481468ed627fec09c08a598..b1709b06a7d800a7fbd671bbf239c113359b05dd 100644
--- a/lib/platform/github/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/github/__snapshots__/index.spec.ts.snap
@@ -1349,6 +1349,63 @@ Array [
 ]
 `;
 
+exports[`platform/github/index ensureIssue() creates issue with labels 1`] = `
+Array [
+  Object {
+    "graphql": Object {
+      "query": Object {
+        "repository": Object {
+          "__args": Object {
+            "name": "undefined",
+            "owner": "undefined",
+          },
+          "issues": Object {
+            "__args": Object {
+              "first": "100",
+            },
+            "nodes": Object {
+              "body": null,
+              "number": null,
+              "state": null,
+              "title": null,
+            },
+            "pageInfo": Object {
+              "endCursor": null,
+              "hasNextPage": null,
+            },
+          },
+        },
+      },
+    },
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "token abc123",
+      "content-length": "425",
+      "content-type": "application/json",
+      "host": "api.github.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "POST",
+    "url": "https://api.github.com/graphql",
+  },
+  Object {
+    "body": "{\\"title\\":\\"new-title\\",\\"body\\":\\"new-content\\",\\"labels\\":[\\"Renovate\\",\\"Maintenance\\"]}",
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "token abc123",
+      "content-length": "78",
+      "content-type": "application/json",
+      "host": "api.github.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "POST",
+    "url": "https://api.github.com/repos/undefined/issues",
+  },
+]
+`;
+
 exports[`platform/github/index ensureIssue() deletes if duplicate 1`] = `
 Array [
   Object {
@@ -1636,6 +1693,74 @@ Array [
 ]
 `;
 
+exports[`platform/github/index ensureIssue() updates issue with labels 1`] = `
+Array [
+  Object {
+    "graphql": Object {
+      "query": Object {
+        "repository": Object {
+          "__args": Object {
+            "name": "undefined",
+            "owner": "undefined",
+          },
+          "issues": Object {
+            "__args": Object {
+              "first": "100",
+            },
+            "nodes": Object {
+              "body": null,
+              "number": null,
+              "state": null,
+              "title": null,
+            },
+            "pageInfo": Object {
+              "endCursor": null,
+              "hasNextPage": null,
+            },
+          },
+        },
+      },
+    },
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "token abc123",
+      "content-length": "425",
+      "content-type": "application/json",
+      "host": "api.github.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "POST",
+    "url": "https://api.github.com/graphql",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "token abc123",
+      "host": "api.github.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "GET",
+    "url": "https://api.github.com/repos/undefined/issues/2",
+  },
+  Object {
+    "body": "{\\"body\\":\\"newer-content\\",\\"state\\":\\"open\\",\\"title\\":\\"title-3\\",\\"labels\\":[\\"Renovate\\",\\"Maintenance\\"]}",
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "token abc123",
+      "content-length": "93",
+      "content-type": "application/json",
+      "host": "api.github.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "PATCH",
+    "url": "https://api.github.com/repos/undefined/issues/2",
+  },
+]
+`;
+
 exports[`platform/github/index ensureIssueClosing() closes issue 1`] = `
 Array [
   Object {
diff --git a/lib/platform/github/index.spec.ts b/lib/platform/github/index.spec.ts
index ed7d87995ea995f042e1347f68639c33d04849bb..2cbf5fd73912c703223399c595c3cdb24cb8e51b 100644
--- a/lib/platform/github/index.spec.ts
+++ b/lib/platform/github/index.spec.ts
@@ -1180,6 +1180,36 @@ describe(getName(), () => {
       expect(res).toBeNull();
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+
+    it('creates issue with labels', async () => {
+      httpMock
+        .scope(githubApiHost)
+        .post('/graphql')
+        .reply(200, {
+          data: {
+            repository: {
+              issues: {
+                pageInfo: {
+                  startCursor: null,
+                  hasNextPage: false,
+                  endCursor: null,
+                },
+                nodes: [],
+              },
+            },
+          },
+        })
+        .post('/repos/undefined/issues')
+        .reply(200);
+      const res = await github.ensureIssue({
+        title: 'new-title',
+        body: 'new-content',
+        labels: ['Renovate', 'Maintenance'],
+      });
+      expect(res).toEqual('created');
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
+
     it('closes others if ensuring only once', async () => {
       httpMock
         .scope(githubApiHost)
@@ -1266,6 +1296,50 @@ describe(getName(), () => {
       expect(res).toEqual('updated');
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+
+    it('updates issue with labels', async () => {
+      httpMock
+        .scope(githubApiHost)
+        .post('/graphql')
+        .reply(200, {
+          data: {
+            repository: {
+              issues: {
+                pageInfo: {
+                  startCursor: null,
+                  hasNextPage: false,
+                  endCursor: null,
+                },
+                nodes: [
+                  {
+                    number: 2,
+                    state: 'open',
+                    title: 'title-2',
+                  },
+                  {
+                    number: 1,
+                    state: 'open',
+                    title: 'title-1',
+                  },
+                ],
+              },
+            },
+          },
+        })
+        .get('/repos/undefined/issues/2')
+        .reply(200, { body: 'new-content' })
+        .patch('/repos/undefined/issues/2')
+        .reply(200);
+      const res = await github.ensureIssue({
+        title: 'title-3',
+        reuseTitle: 'title-2',
+        body: 'newer-content',
+        labels: ['Renovate', 'Maintenance'],
+      });
+      expect(res).toEqual('updated');
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
+
     it('skips update if unchanged', async () => {
       httpMock
         .scope(githubApiHost)
diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts
index 0363732eee9cc61fa7bc41f1e98b7c45bfbad532..61f32c3cf7c21d9331a4c28b378026ea796dae77 100644
--- a/lib/platform/github/index.ts
+++ b/lib/platform/github/index.ts
@@ -1152,6 +1152,7 @@ export async function ensureIssue({
   title,
   reuseTitle,
   body: rawBody,
+  labels,
   once = false,
   shouldReOpen = true,
 }: EnsureIssueConfig): Promise<EnsureIssueResult | null> {
@@ -1206,7 +1207,7 @@ export async function ensureIssue({
             issue.number
           }`,
           {
-            body: { body, state: 'open', title },
+            body: { body, state: 'open', title, labels },
           }
         );
         logger.debug('Issue updated');
@@ -1219,6 +1220,7 @@ export async function ensureIssue({
         body: {
           title,
           body,
+          labels,
         },
       }
     );
diff --git a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
index 6be6e08090f43998a1fcd82f11b49fbb2d27b527..d1499c65bebe09c5c93e9f83c842cecdaf3dd44b 100644
--- a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
@@ -700,6 +700,36 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab/index ensureIssue() sets issue labels 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/undefined/issues?per_page=100&author_id=undefined&state=opened",
+  },
+  Object {
+    "body": "{\\"title\\":\\"new-title\\",\\"description\\":\\"new-content\\",\\"labels\\":[\\"Renovate\\",\\"Maintenance\\"]}",
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "Bearer abc123",
+      "content-length": "85",
+      "content-type": "application/json",
+      "host": "gitlab.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "POST",
+    "url": "https://gitlab.com/api/v4/projects/undefined/issues",
+  },
+]
+`;
+
 exports[`platform/gitlab/index ensureIssue() skips update if unchanged 1`] = `
 Array [
   Object {
@@ -768,6 +798,47 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab/index ensureIssue() updates issue with labels 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/undefined/issues?per_page=100&author_id=undefined&state=opened",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/undefined/issues/2",
+  },
+  Object {
+    "body": "{\\"title\\":\\"title-2\\",\\"description\\":\\"newer-content\\",\\"labels\\":[\\"Renovate\\",\\"Maintenance\\"]}",
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate, br",
+      "authorization": "Bearer abc123",
+      "content-length": "85",
+      "content-type": "application/json",
+      "host": "gitlab.com",
+      "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
+    },
+    "method": "PUT",
+    "url": "https://gitlab.com/api/v4/projects/undefined/issues/2",
+  },
+]
+`;
+
 exports[`platform/gitlab/index ensureIssueClosing() closes issue 1`] = `
 Array [
   Object {
diff --git a/lib/platform/gitlab/index.spec.ts b/lib/platform/gitlab/index.spec.ts
index 76a0a00e125017624e2bd79dd85e5c4b44b6d832..1deb9edbbf1d01995c3fd9bd50e11349e56d3178 100644
--- a/lib/platform/gitlab/index.spec.ts
+++ b/lib/platform/gitlab/index.spec.ts
@@ -742,6 +742,25 @@ describe(getName(), () => {
       expect(res).toEqual('created');
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+
+    it('sets issue labels', async () => {
+      httpMock
+        .scope(gitlabApiHost)
+        .get(
+          '/api/v4/projects/undefined/issues?per_page=100&author_id=undefined&state=opened'
+        )
+        .reply(200, [])
+        .post('/api/v4/projects/undefined/issues')
+        .reply(200);
+      const res = await gitlab.ensureIssue({
+        title: 'new-title',
+        body: 'new-content',
+        labels: ['Renovate', 'Maintenance'],
+      });
+      expect(res).toEqual('created');
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
+
     it('updates issue', async () => {
       httpMock
         .scope(gitlabApiHost)
@@ -769,6 +788,36 @@ describe(getName(), () => {
       expect(res).toEqual('updated');
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+
+    it('updates issue with labels', async () => {
+      httpMock
+        .scope(gitlabApiHost)
+        .get(
+          '/api/v4/projects/undefined/issues?per_page=100&author_id=undefined&state=opened'
+        )
+        .reply(200, [
+          {
+            iid: 1,
+            title: 'title-1',
+          },
+          {
+            iid: 2,
+            title: 'title-2',
+          },
+        ])
+        .get('/api/v4/projects/undefined/issues/2')
+        .reply(200, { description: 'new-content' })
+        .put('/api/v4/projects/undefined/issues/2')
+        .reply(200);
+      const res = await gitlab.ensureIssue({
+        title: 'title-2',
+        body: 'newer-content',
+        labels: ['Renovate', 'Maintenance'],
+      });
+      expect(res).toEqual('updated');
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
+
     it('skips update if unchanged', async () => {
       httpMock
         .scope(gitlabApiHost)
diff --git a/lib/platform/gitlab/index.ts b/lib/platform/gitlab/index.ts
old mode 100755
new mode 100644
index da190b10893409da0906d8ade34020f8422e1d60..4a585f3a28250d5bd368fd6adc080d7e726e1fd7
--- a/lib/platform/gitlab/index.ts
+++ b/lib/platform/gitlab/index.ts
@@ -793,6 +793,7 @@ export async function ensureIssue({
   title,
   reuseTitle,
   body,
+  labels,
 }: EnsureIssueConfig): Promise<'updated' | 'created' | null> {
   logger.debug(`ensureIssue()`);
   const description = massageMarkdown(sanitize(body));
@@ -813,7 +814,7 @@ export async function ensureIssue({
         await gitlabApi.putJson(
           `projects/${config.repository}/issues/${issue.iid}`,
           {
-            body: { title, description },
+            body: { title, description, labels },
           }
         );
         return 'updated';
@@ -823,6 +824,7 @@ export async function ensureIssue({
         body: {
           title,
           description,
+          labels,
         },
       });
       logger.info('Issue created');
diff --git a/lib/platform/types.ts b/lib/platform/types.ts
index dc73dda2298009adc455b927d33f4f2fee128cc8..150e6d1818e40636dfd06a23f5bd76ff9382037d 100644
--- a/lib/platform/types.ts
+++ b/lib/platform/types.ts
@@ -98,6 +98,7 @@ export interface EnsureIssueConfig {
   title: string;
   reuseTitle?: string;
   body: string;
+  labels?: string[];
   once?: boolean;
   shouldReOpen?: boolean;
 }
diff --git a/lib/workers/repository/dependency-dashboard.spec.ts b/lib/workers/repository/dependency-dashboard.spec.ts
index 8968713df9882bf7ec49687f5c0ddfcdbb28bc32..9a2e323835e43f68b17ba9cf53c0a60543060ce7 100644
--- a/lib/workers/repository/dependency-dashboard.spec.ts
+++ b/lib/workers/repository/dependency-dashboard.spec.ts
@@ -517,5 +517,20 @@ describe(getName(), () => {
       await dependencyDashboard.ensureDependencyDashboard(config, branches);
       expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
     });
+
+    it('forwards configured labels to the ensure issue call', async () => {
+      const branches: BranchConfig[] = [];
+      config.dependencyDashboard = true;
+      config.dependencyDashboardLabels = ['RenovateBot', 'Maintenance'];
+      await dependencyDashboard.ensureDependencyDashboard(config, branches);
+      expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+      expect(platform.ensureIssue.mock.calls[0][0].labels).toStrictEqual([
+        'RenovateBot',
+        'Maintenance',
+      ]);
+
+      // same with dry run
+      await dryRun(branches, platform);
+    });
   });
 });
diff --git a/lib/workers/repository/dependency-dashboard.ts b/lib/workers/repository/dependency-dashboard.ts
index 04c03feaa88018d7e7937ca862e1c9f9c68f7604..6e1072c81deb6a89192e27fced93b87ee26f9113 100644
--- a/lib/workers/repository/dependency-dashboard.ts
+++ b/lib/workers/repository/dependency-dashboard.ts
@@ -349,6 +349,7 @@ export async function ensureDependencyDashboard(
       title: config.dependencyDashboardTitle,
       reuseTitle,
       body: issueBody,
+      labels: config.dependencyDashboardLabels,
     });
   }
 }