diff --git a/data/debian-distro-info.json b/data/debian-distro-info.json
new file mode 100644
index 0000000000000000000000000000000000000000..29e555c654d344c0c9ea8fce371824aa4da536d0
--- /dev/null
+++ b/data/debian-distro-info.json
@@ -0,0 +1,133 @@
+{
+  "v1.1": {
+    "codename": "Buzz",
+    "series": "buzz",
+    "created": "1993-08-16",
+    "release": "1996-06-17",
+    "eol": "1997-06-05"
+  },
+  "v1.2": {
+    "codename": "Rex",
+    "series": "rex",
+    "created": "1996-06-17",
+    "release": "1996-12-12",
+    "eol": "1998-06-05"
+  },
+  "v1.3": {
+    "codename": "Bo",
+    "series": "bo",
+    "created": "1996-12-12",
+    "release": "1997-06-05",
+    "eol": "1999-03-09"
+  },
+  "v2": {
+    "codename": "Hamm",
+    "series": "hamm",
+    "created": "1997-06-05",
+    "release": "1998-07-24",
+    "eol": "2000-03-09"
+  },
+  "v2.1": {
+    "codename": "Slink",
+    "series": "slink",
+    "created": "1998-07-24",
+    "release": "1999-03-09",
+    "eol": "2000-10-30"
+  },
+  "v2.2": {
+    "codename": "Potato",
+    "series": "potato",
+    "created": "1999-03-09",
+    "release": "2000-08-15",
+    "eol": "2003-07-30"
+  },
+  "v3": {
+    "codename": "Woody",
+    "series": "woody",
+    "created": "2000-08-15",
+    "release": "2002-07-19",
+    "eol": "2006-06-30"
+  },
+  "v3.1": {
+    "codename": "Sarge",
+    "series": "sarge",
+    "created": "2002-07-19",
+    "release": "2005-06-06",
+    "eol": "2008-03-30"
+  },
+  "v4": {
+    "codename": "Etch",
+    "series": "etch",
+    "created": "2005-06-06",
+    "release": "2007-04-08",
+    "eol": "2010-02-15"
+  },
+  "v5": {
+    "codename": "Lenny",
+    "series": "lenny",
+    "created": "2007-04-08",
+    "release": "2009-02-14",
+    "eol": "2012-02-06"
+  },
+  "v6": {
+    "codename": "Squeeze",
+    "series": "squeeze",
+    "created": "2009-02-14",
+    "release": "2011-02-06",
+    "eol": "2014-05-31",
+    "eol_lts": "2016-02-29"
+  },
+  "v7": {
+    "codename": "Wheezy",
+    "series": "wheezy",
+    "created": "2011-02-06",
+    "release": "2013-05-04",
+    "eol": "2016-04-26",
+    "eol_lts": "2018-05-31",
+    "eol_elts": "2020-06-30"
+  },
+  "v8": {
+    "codename": "Jessie",
+    "series": "jessie",
+    "created": "2013-05-04",
+    "release": "2015-04-25",
+    "eol": "2018-06-17",
+    "eol_lts": "2020-06-30",
+    "eol_elts": "2022-06-30"
+  },
+  "v9": {
+    "codename": "Stretch",
+    "series": "stretch",
+    "created": "2015-04-25",
+    "release": "2017-06-17",
+    "eol": "2020-07-06",
+    "eol_lts": "2022-06-30",
+    "eol_elts": "2024-06-30"
+  },
+  "v10": {
+    "codename": "Buster",
+    "series": "buster",
+    "created": "2017-06-17",
+    "release": "2019-07-06",
+    "eol": "2022-08-14",
+    "eol_lts": "2024-06-30",
+    "eol_elts": "2026-06-30"
+  },
+  "v11": {
+    "codename": "Bullseye",
+    "series": "bullseye",
+    "created": "2019-07-06",
+    "release": "2021-08-14",
+    "eol": "2024-08-14"
+  },
+  "v12": {
+    "codename": "Bookworm",
+    "series": "bookworm",
+    "created": "2021-08-14"
+  },
+  "v13": {
+    "codename": "Trixie",
+    "series": "trixie",
+    "created": "2023-08-01"
+  }
+}
diff --git a/data/ubuntu-distro-info.json b/data/ubuntu-distro-info.json
index d5db78682c4000452650065548b5e416f6639bc3..6c8ff25b2e89969b09f36d82ae16a5bacd134e55 100644
--- a/data/ubuntu-distro-info.json
+++ b/data/ubuntu-distro-info.json
@@ -265,5 +265,12 @@
     "eol": "2027-04-21",
     "eol_server": "2027-04-21",
     "eol_esm": "2032-04-21"
+  },
+  "v22.10": {
+    "codename": "Kinetic Kudu",
+    "series": "kinetic",
+    "created": "2022-04-21",
+    "release": "2022-10-20",
+    "eol": "2023-07-20"
   }
 }
diff --git a/docs/usage/docker.md b/docs/usage/docker.md
index c891704e7e113dd8ba380c83f31f25c89912640b..896f51f5c476fa54b72a6c87a69cd1cb5f05b112 100644
--- a/docs/usage/docker.md
+++ b/docs/usage/docker.md
@@ -132,12 +132,30 @@ For example, Renovate will offer to upgrade the following `Dockerfile` layer:
 FROM ubuntu:yakkety
 ```
 
-To
+To:
 
 ```dockerfile
 FROM ubuntu:focal
 ```
 
+### Debian codenames
+
+Renovate understands [Debian release code names and rolling updates schedule](https://wiki.debian.org/DebianReleases) and will offer upgrades to the latest stable release (e.g. from `debian:stretch` to `debian:bullseye`).
+
+For this to work the codename must be in lowercase.
+
+For example, Renovate will offer to upgrade the following `Dockerfile` layer:
+
+```dockerfile
+FROM debian:buster
+```
+
+To:
+
+```dockerfile
+FROM debian:bullseye
+```
+
 ## Configuring/Disabling
 
 If you wish to make changes that apply to all Docker managers, then add them to the `docker` config object.
diff --git a/lib/modules/manager/dockerfile/extract.spec.ts b/lib/modules/manager/dockerfile/extract.spec.ts
index 9f64b74af4d33d76eaafd00453205609e0da0779..81c8a91e4e464f923204d65cec2d48a8ee0b2d7f 100644
--- a/lib/modules/manager/dockerfile/extract.spec.ts
+++ b/lib/modules/manager/dockerfile/extract.spec.ts
@@ -594,6 +594,41 @@ describe('modules/manager/dockerfile/extract', () => {
       `);
     });
 
+    it('handles debian with codename', () => {
+      const res = extractPackageFile('FROM debian:buster\n').deps;
+      expect(res).toEqual([
+        {
+          autoReplaceStringTemplate:
+            '{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
+          currentDigest: undefined,
+          currentValue: 'buster',
+          datasource: 'docker',
+          depName: 'debian',
+          depType: 'final',
+          replaceString: 'debian:buster',
+          versioning: 'debian',
+        },
+      ]);
+    });
+
+    it('handles debian with prefixes', () => {
+      const res = extractPackageFile('FROM amd64/debian:10\n').deps;
+      expect(res).toEqual([
+        {
+          autoReplaceStringTemplate:
+            '{{packageName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
+          currentDigest: undefined,
+          currentValue: '10',
+          datasource: 'docker',
+          depName: 'debian',
+          depType: 'final',
+          packageName: 'amd64/debian',
+          replaceString: 'amd64/debian:10',
+          versioning: 'debian',
+        },
+      ]);
+    });
+
     it('handles prefixes', () => {
       const res = extractPackageFile('FROM amd64/ubuntu:18.04\n').deps;
       expect(res).toMatchInlineSnapshot(`
diff --git a/lib/modules/manager/dockerfile/extract.ts b/lib/modules/manager/dockerfile/extract.ts
index ab77bc144fefecb2e282fde287d58b6b79faacd6..6dc2b0d869cd9aeefd2f127650df28758353a6e3 100644
--- a/lib/modules/manager/dockerfile/extract.ts
+++ b/lib/modules/manager/dockerfile/extract.ts
@@ -2,6 +2,7 @@ import is from '@sindresorhus/is';
 import { logger } from '../../../logger';
 import { regEx } from '../../../util/regex';
 import { DockerDatasource } from '../../datasource/docker';
+import * as debianVersioning from '../../versioning/debian';
 import * as ubuntuVersioning from '../../versioning/ubuntu';
 import type { PackageDependency, PackageFile } from '../types';
 
@@ -140,6 +141,10 @@ export function getDep(
     dep.versioning = ubuntuVersioning.id;
   }
 
+  if (dep.depName === 'debian') {
+    dep.versioning = debianVersioning.id;
+  }
+
   // Don't display quay.io ports
   if (dep.depName && quayRegex.test(dep.depName)) {
     const depName = dep.depName.replace(quayRegex, 'quay.io');
diff --git a/lib/modules/versioning/api.ts b/lib/modules/versioning/api.ts
index a76a544750e28a466c581fefeccc06ccffde9ed5..5edcdcccc857111d38d3465fb6097466e35296f3 100644
--- a/lib/modules/versioning/api.ts
+++ b/lib/modules/versioning/api.ts
@@ -2,6 +2,7 @@ import * as amazonMachineImage from './aws-machine-image';
 import * as cargo from './cargo';
 import * as composer from './composer';
 import * as conan from './conan';
+import * as debian from './debian';
 import * as docker from './docker';
 import * as git from './git';
 import * as gradle from './gradle';
@@ -32,6 +33,7 @@ api.set(amazonMachineImage.id, amazonMachineImage.api);
 api.set('cargo', cargo.api);
 api.set('composer', composer.api);
 api.set('conan', conan.api);
+api.set('debian', debian.api);
 api.set('docker', docker.api);
 api.set('git', git.api);
 api.set('gradle', gradle.api);
diff --git a/lib/modules/versioning/debian/common.ts b/lib/modules/versioning/debian/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6341489abcc3e02080fe1772893ce62b58a39c22
--- /dev/null
+++ b/lib/modules/versioning/debian/common.ts
@@ -0,0 +1,77 @@
+import { DateTime } from 'luxon';
+import { logger } from '../../../logger';
+import type { DistroInfo, DistroInfoRecordWithVersion } from '../distro';
+
+const refreshInterval = { days: 1 };
+
+export class RollingReleasesData {
+  private ltsToVer = new Map<string, DistroInfoRecordWithVersion>();
+  private verToLts = new Map<string, DistroInfoRecordWithVersion>();
+  private timestamp = DateTime.fromMillis(0).toUTC(); // start of epoch
+  private distroInfo: DistroInfo;
+
+  constructor(distroInfo: DistroInfo) {
+    this.distroInfo = distroInfo;
+  }
+
+  getVersionByLts(input: string): string {
+    this.build();
+    const schedule = this.ltsToVer.get(input);
+    if (schedule) {
+      return schedule.version;
+    }
+    return input;
+  }
+
+  getLtsByVersion(input: string): string {
+    this.build();
+    const di = this.verToLts.get(input);
+    if (di) {
+      return di.series;
+    }
+    return input;
+  }
+
+  has(version: string): boolean {
+    this.build();
+    return this.ltsToVer.has(version);
+  }
+
+  schedule(version: string): DistroInfoRecordWithVersion | undefined {
+    this.build();
+    let schedule: DistroInfoRecordWithVersion | undefined = undefined;
+    if (this.verToLts.has(version)) {
+      schedule = this.verToLts.get(version);
+    }
+    if (this.ltsToVer.has(version)) {
+      schedule = this.ltsToVer.get(version);
+    }
+    return schedule;
+  }
+
+  private build(): void {
+    const now = DateTime.now().toUTC();
+    if (now < this.timestamp.plus(refreshInterval)) {
+      return;
+    }
+    logger.debug('RollingReleasesData - data written');
+    this.timestamp = now;
+    for (let i = 0; i < 3; i++) {
+      const di = this.distroInfo.getNLatest(i);
+
+      // istanbul ignore if: should never happen
+      if (!di) {
+        return;
+      }
+
+      let prefix = '';
+      for (let j = 0; j < i; j++) {
+        prefix += 'old';
+      }
+      di.series = prefix + 'stable';
+
+      this.ltsToVer.set(di.series, di);
+      this.verToLts.set(di.version, di);
+    }
+  }
+}
diff --git a/lib/modules/versioning/debian/index.spec.ts b/lib/modules/versioning/debian/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a5406dc4c6d07557279148af2348ed6be367042e
--- /dev/null
+++ b/lib/modules/versioning/debian/index.spec.ts
@@ -0,0 +1,428 @@
+import { DateTime, Settings } from 'luxon';
+import { logger } from '../../../logger';
+import { DebianVersioningApi } from '.';
+
+describe('modules/versioning/debian/index', () => {
+  const dt = DateTime.fromISO('2022-04-20');
+
+  const spy = jest.spyOn(Settings, 'now');
+  const debian = new DebianVersioningApi();
+
+  beforeEach(() => {
+    spy.mockReturnValue(dt.valueOf());
+  });
+
+  afterEach(() => {
+    jest.resetAllMocks();
+  });
+
+  it.each`
+    version           | expected
+    ${undefined}      | ${false}
+    ${null}           | ${false}
+    ${''}             | ${false}
+    ${'buzz'}         | ${true}
+    ${'rex'}          | ${true}
+    ${'bo'}           | ${true}
+    ${'hamm'}         | ${true}
+    ${'slink'}        | ${true}
+    ${'potato'}       | ${true}
+    ${'woody'}        | ${true}
+    ${'sarge'}        | ${true}
+    ${'etch'}         | ${true}
+    ${'lenny'}        | ${true}
+    ${'squeeze'}      | ${true}
+    ${'wheezy'}       | ${true}
+    ${'jessie'}       | ${true}
+    ${'stretch'}      | ${true}
+    ${'buster'}       | ${true}
+    ${'Buster'}       | ${false}
+    ${'bullseye'}     | ${true}
+    ${'bookworm'}     | ${false}
+    ${'trixie'}       | ${false}
+    ${'sid'}          | ${false}
+    ${'1.1'}          | ${true}
+    ${'1.2'}          | ${true}
+    ${'1.3'}          | ${true}
+    ${'2'}            | ${true}
+    ${'2.1'}          | ${true}
+    ${'2.2'}          | ${true}
+    ${'3'}            | ${true}
+    ${'4'}            | ${true}
+    ${'5'}            | ${true}
+    ${'6'}            | ${true}
+    ${'7'}            | ${true}
+    ${'8'}            | ${true}
+    ${'9'}            | ${true}
+    ${'10'}           | ${true}
+    ${'10-slim'}      | ${false}
+    ${'11'}           | ${true}
+    ${'12'}           | ${false}
+    ${'13'}           | ${false}
+    ${'sid'}          | ${false}
+    ${'stable'}       | ${true}
+    ${'oldstable'}    | ${true}
+    ${'oldoldstable'} | ${true}
+    ${'experimental'} | ${false}
+  `('isValid("$version") === $expected', ({ version, expected }) => {
+    spy.mockReturnValue(dt.valueOf());
+    expect(debian.isValid(version)).toBe(expected);
+  });
+
+  it.each`
+    version           | range        | expected
+    ${undefined}      | ${undefined} | ${false}
+    ${null}           | ${undefined} | ${false}
+    ${''}             | ${undefined} | ${false}
+    ${'7'}            | ${undefined} | ${true}
+    ${'11'}           | ${undefined} | ${true}
+    ${'12'}           | ${undefined} | ${false}
+    ${'stable'}       | ${undefined} | ${true}
+    ${'oldstable'}    | ${undefined} | ${true}
+    ${'oldoldstable'} | ${undefined} | ${true}
+    ${'wheezy'}       | ${undefined} | ${true}
+    ${'bullseye'}     | ${undefined} | ${true}
+    ${'bookworm'}     | ${undefined} | ${false}
+  `(
+    'isCompatible("$version") === $expected',
+    ({ version, range, expected }) => {
+      expect(debian.isCompatible(version, range)).toBe(expected);
+    }
+  );
+
+  it.each`
+    version      | expected
+    ${undefined} | ${false}
+    ${null}      | ${false}
+    ${''}        | ${false}
+    ${'6'}       | ${true}
+    ${'>=6'}     | ${false}
+  `('isSingleVersion("$version") === $expected', ({ version, expected }) => {
+    expect(debian.isSingleVersion(version)).toBe(expected);
+  });
+
+  it.each`
+    version           | expected
+    ${undefined}      | ${false}
+    ${null}           | ${false}
+    ${''}             | ${false}
+    ${'buzz'}         | ${false}
+    ${'rex'}          | ${false}
+    ${'bo'}           | ${false}
+    ${'hamm'}         | ${false}
+    ${'slink'}        | ${false}
+    ${'potato'}       | ${false}
+    ${'woody'}        | ${false}
+    ${'sarge'}        | ${false}
+    ${'etch'}         | ${false}
+    ${'lenny'}        | ${false}
+    ${'squeeze'}      | ${false}
+    ${'wheezy'}       | ${false}
+    ${'jessie'}       | ${false}
+    ${'stretch'}      | ${true}
+    ${'buster'}       | ${true}
+    ${'bullseye'}     | ${true}
+    ${'bookworm'}     | ${false}
+    ${'trixie'}       | ${false}
+    ${'sid'}          | ${false}
+    ${'1.1'}          | ${false}
+    ${'1.2'}          | ${false}
+    ${'1.3'}          | ${false}
+    ${'2'}            | ${false}
+    ${'2.1'}          | ${false}
+    ${'2.2'}          | ${false}
+    ${'3'}            | ${false}
+    ${'4'}            | ${false}
+    ${'5'}            | ${false}
+    ${'6'}            | ${false}
+    ${'7'}            | ${false}
+    ${'8'}            | ${false}
+    ${'9'}            | ${true}
+    ${'10'}           | ${true}
+    ${'11'}           | ${true}
+    ${'12'}           | ${false}
+    ${'13'}           | ${false}
+    ${'sid'}          | ${false}
+    ${'experimental'} | ${false}
+    ${'stable'}       | ${true}
+    ${'oldstable'}    | ${true}
+    ${'oldoldstable'} | ${true}
+  `('isStable("$version") === $expected', ({ version, expected }) => {
+    spy.mockReturnValue(dt.valueOf());
+    expect(debian.isStable(version)).toBe(expected);
+  });
+
+  it.each`
+    version
+    ${'10'}
+    ${'11'}
+    ${'12'}
+    ${'13'}
+    ${'sid'}
+    ${'experimental'}
+    ${'stable'}
+    ${'oldstable'}
+    ${'oldoldstable'}
+  `(
+    'ensures that rolling release is not refreshed within frame time window',
+    ({ version, expected }) => {
+      debian.isStable(version);
+      expect(logger.debug).toHaveBeenCalledTimes(0);
+    }
+  );
+
+  it('checks runtime date handling & refresh rolling release data', () => {
+    const future = DateTime.now().toUTC().plus({ year: 3 }).valueOf();
+    const past = DateTime.fromISO('2019-08-06', { zone: 'UTC' }).valueOf();
+    spy.mockReturnValue(past);
+    expect(debian.isStable('buster')).toBeTrue();
+    spy.mockReturnValue(future);
+    expect(debian.isStable('buster')).toBeFalse();
+    expect(logger.debug).toHaveBeenCalledTimes(1);
+    expect(logger.debug).toHaveBeenCalledWith(
+      'RollingReleasesData - data written'
+    );
+  });
+
+  it.each`
+    version           | expected
+    ${undefined}      | ${false}
+    ${null}           | ${false}
+    ${''}             | ${false}
+    ${'02.10'}        | ${false}
+    ${'04.10'}        | ${false}
+    ${'05.04'}        | ${false}
+    ${'6.06'}         | ${false}
+    ${'8.04'}         | ${false}
+    ${'9.04'}         | ${false}
+    ${'buzz'}         | ${true}
+    ${'rex'}          | ${true}
+    ${'bo'}           | ${true}
+    ${'hamm'}         | ${true}
+    ${'slink'}        | ${true}
+    ${'potato'}       | ${true}
+    ${'woody'}        | ${true}
+    ${'sarge'}        | ${true}
+    ${'etch'}         | ${true}
+    ${'lenny'}        | ${true}
+    ${'squeeze'}      | ${true}
+    ${'wheezy'}       | ${true}
+    ${'jessie'}       | ${true}
+    ${'stretch'}      | ${true}
+    ${'buster'}       | ${true}
+    ${'bullseye'}     | ${true}
+    ${'bookworm'}     | ${false}
+    ${'trixie'}       | ${false}
+    ${'sid'}          | ${false}
+    ${'1.1'}          | ${true}
+    ${'1.2'}          | ${true}
+    ${'1.3'}          | ${true}
+    ${'2'}            | ${true}
+    ${'2.1'}          | ${true}
+    ${'2.2'}          | ${true}
+    ${'3'}            | ${true}
+    ${'4'}            | ${true}
+    ${'5'}            | ${true}
+    ${'6'}            | ${true}
+    ${'7'}            | ${true}
+    ${'8'}            | ${true}
+    ${'9'}            | ${true}
+    ${'10'}           | ${true}
+    ${'11'}           | ${true}
+    ${'12'}           | ${false}
+    ${'13'}           | ${false}
+    ${'sid'}          | ${false}
+    ${'experimental'} | ${false}
+    ${'Bookworm'}     | ${false}
+    ${'Sid'}          | ${false}
+    ${'Potato-'}      | ${false}
+    ${'Woody'}        | ${false}
+    ${'stable'}       | ${true}
+    ${'oldstable'}    | ${true}
+    ${'oldoldstable'} | ${true}
+  `('isVersion("$version") === $expected', ({ version, expected }) => {
+    expect(debian.isVersion(version)).toBe(expected);
+  });
+
+  it.each`
+    version           | major   | minor   | patch
+    ${undefined}      | ${null} | ${null} | ${null}
+    ${null}           | ${null} | ${null} | ${null}
+    ${''}             | ${null} | ${null} | ${null}
+    ${'42'}           | ${null} | ${null} | ${null}
+    ${'2020.04'}      | ${null} | ${null} | ${null}
+    ${'3.1'}          | ${3}    | ${1}    | ${null}
+    ${'1.1'}          | ${1}    | ${1}    | ${null}
+    ${'7'}            | ${7}    | ${null} | ${null}
+    ${'8'}            | ${8}    | ${null} | ${null}
+    ${'9'}            | ${9}    | ${null} | ${null}
+    ${'10'}           | ${10}   | ${null} | ${null}
+    ${'oldoldstable'} | ${9}    | ${null} | ${null}
+    ${'oldstable'}    | ${10}   | ${null} | ${null}
+    ${'stable'}       | ${11}   | ${null} | ${null}
+  `(
+    'getMajor, getMinor, getPatch for "$version"',
+    ({ version, major, minor, patch }) => {
+      expect(debian.getMajor(version)).toBe(major);
+      expect(debian.getMinor(version)).toBe(minor);
+      expect(debian.getPatch(version)).toBe(patch);
+    }
+  );
+
+  it.each`
+    a                 | b                 | expected
+    ${'woody'}        | ${'sarge'}        | ${false}
+    ${'lenny'}        | ${'3'}            | ${false}
+    ${'lenny'}        | ${'5'}            | ${true}
+    ${'squeeze'}      | ${'6'}            | ${true}
+    ${'10'}           | ${'buster'}       | ${true}
+    ${'6'}            | ${'squeeze'}      | ${true}
+    ${'buster'}       | ${'10'}           | ${true}
+    ${'oldoldstable'} | ${'9'}            | ${true}
+    ${'oldstable'}    | ${'10'}           | ${true}
+    ${'stable'}       | ${'11'}           | ${true}
+    ${'9'}            | ${'oldoldstable'} | ${true}
+    ${'10'}           | ${'oldstable'}    | ${true}
+    ${'11'}           | ${'stable'}       | ${true}
+  `('equals($a, $b) === $expected', ({ a, b, expected }) => {
+    expect(debian.equals(a, b)).toBe(expected);
+  });
+
+  it.each`
+    a                 | b                 | expected
+    ${'5'}            | ${'6'}            | ${false}
+    ${'6'}            | ${'5'}            | ${true}
+    ${'5'}            | ${'10'}           | ${false}
+    ${'11'}           | ${'10'}           | ${true}
+    ${'5'}            | ${'6'}            | ${false}
+    ${'11'}           | ${'1.1'}          | ${true}
+    ${'xxx'}          | ${'yyy'}          | ${true}
+    ${'yyy'}          | ${'xxx'}          | ${true}
+    ${'lenny'}        | ${'squeeze'}      | ${false}
+    ${'squeeze'}      | ${'lenny'}        | ${true}
+    ${'lenny'}        | ${'buster'}       | ${false}
+    ${'bookworm'}     | ${'etch'}         | ${true}
+    ${'sarge'}        | ${'bo'}           | ${true}
+    ${'bullseye'}     | ${'rex'}          | ${true}
+    ${'buzz'}         | ${'jessie'}       | ${false}
+    ${'oldoldstable'} | ${'8'}            | ${true}
+    ${'oldstable'}    | ${'oldoldstable'} | ${true}
+    ${'stable'}       | ${'oldstable'}    | ${true}
+    ${'11'}           | ${'oldoldstable'} | ${true}
+    ${'10'}           | ${'oldstable'}    | ${false}
+    ${'9'}            | ${'stable'}       | ${false}
+  `('isGreaterThan("$a", "$b") === $expected', ({ a, b, expected }) => {
+    expect(debian.isGreaterThan(a, b)).toBe(expected);
+  });
+
+  it.each`
+    versions                                            | range         | expected
+    ${['8', '9', '10', '11']}                           | ${'2020.04'}  | ${null}
+    ${['8', '9', '10', '11']}                           | ${'foobar'}   | ${null}
+    ${['8', '9', '10', '11']}                           | ${'11'}       | ${'11'}
+    ${['8', '9', '10', '11']}                           | ${'10'}       | ${'10'}
+    ${['8', '9', '10', '11']}                           | ${'4'}        | ${null}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'2020.04'}  | ${null}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'foobar'}   | ${null}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'bullseye'} | ${'bullseye'}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'buster'}   | ${'buster'}
+    ${['jessie', 'stretch', 'buster', 'stable']}        | ${'stable'}   | ${'stable'}
+    ${['jessie', 'stretch', 'oldstable', 'bullseye']}   | ${'buster'}   | ${'oldstable'}
+    ${['jessie', 'oldoldstable', 'buster', 'bullseye']} | ${'warty'}    | ${null}
+  `(
+    'getSatisfyingVersion($versions, "$range") === "$expected"',
+    ({ versions, range, expected }) => {
+      expect(debian.getSatisfyingVersion(versions, range)).toBe(expected);
+    }
+  );
+
+  it.each`
+    versions                                            | range         | expected
+    ${['8', '9', '10', '11']}                           | ${'2020.04'}  | ${null}
+    ${['8', '9', '10', '11']}                           | ${'foobar'}   | ${null}
+    ${['8', '9', '10', '11']}                           | ${'11'}       | ${'11'}
+    ${['8', '9', '10', '11']}                           | ${'10'}       | ${'10'}
+    ${['8', '9', '10', '11']}                           | ${'4'}        | ${null}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'2020.04'}  | ${null}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'foobar'}   | ${null}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'bullseye'} | ${'bullseye'}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'buster'}   | ${'buster'}
+    ${['jessie', 'stretch', 'buster', 'bullseye']}      | ${'warty'}    | ${null}
+    ${['jessie', 'stretch', 'buster', 'stable']}        | ${'stable'}   | ${'stable'}
+    ${['jessie', 'stretch', 'oldstable', 'bullseye']}   | ${'buster'}   | ${'oldstable'}
+    ${['jessie', 'oldoldstable', 'buster', 'bullseye']} | ${'warty'}    | ${null}
+  `(
+    'minSatisfyingVersion($versions, "$range") === "$expected"',
+    ({ versions, range, expected }) => {
+      expect(debian.minSatisfyingVersion(versions, range)).toBe(expected);
+    }
+  );
+
+  it.each`
+    currentValue      | rangeStrategy | currentVersion | newVersion    | expected
+    ${undefined}      | ${undefined}  | ${undefined}   | ${'foobar'}   | ${'foobar'}
+    ${'stretch'}      | ${undefined}  | ${undefined}   | ${'11'}       | ${'bullseye'}
+    ${'stretch'}      | ${undefined}  | ${undefined}   | ${'bullseye'} | ${'bullseye'}
+    ${'stretch'}      | ${undefined}  | ${undefined}   | ${'stable'}   | ${'bullseye'}
+    ${'9'}            | ${undefined}  | ${undefined}   | ${'11'}       | ${'11'}
+    ${'oldoldstable'} | ${undefined}  | ${undefined}   | ${'11'}       | ${'stable'}
+    ${'oldstable'}    | ${undefined}  | ${undefined}   | ${'11'}       | ${'stable'}
+    ${'9'}            | ${undefined}  | ${undefined}   | ${'stable'}   | ${'11'}
+    ${'oldstable'}    | ${undefined}  | ${undefined}   | ${'11'}       | ${'stable'}
+    ${'oldstable'}    | ${undefined}  | ${undefined}   | ${'3'}        | ${'3'}
+    ${'oldstable'}    | ${'pin'}      | ${undefined}   | ${'11'}       | ${'11'}
+    ${'oldstable'}    | ${'pin'}      | ${undefined}   | ${'stable'}   | ${'11'}
+    ${'oldstable'}    | ${'pin'}      | ${undefined}   | ${'bullseye'} | ${'11'}
+    ${'buster'}       | ${'pin'}      | ${undefined}   | ${'11'}       | ${'11'}
+    ${'buster'}       | ${'pin'}      | ${undefined}   | ${'stable'}   | ${'11'}
+    ${'buster'}       | ${'pin'}      | ${undefined}   | ${'bullseye'} | ${'11'}
+    ${'10'}           | ${'pin'}      | ${undefined}   | ${'11'}       | ${'11'}
+    ${'10'}           | ${'pin'}      | ${undefined}   | ${'stable'}   | ${'11'}
+    ${'10'}           | ${'pin'}      | ${undefined}   | ${'bullseye'} | ${'11'}
+  `(
+    'getNewValue("$currentValue", "$rangeStrategy", "$currentVersion", "$newVersion") === "$expected"',
+    ({ currentValue, rangeStrategy, currentVersion, newVersion, expected }) => {
+      spy.mockReturnValue(dt.valueOf());
+      expect(
+        debian.getNewValue({
+          currentValue,
+          rangeStrategy,
+          currentVersion,
+          newVersion,
+        })
+      ).toBe(expected);
+    }
+  );
+
+  it.each`
+    a                 | b                 | expected
+    ${'woody'}        | ${'sarge'}        | ${-1}
+    ${'lenny'}        | ${'3'}            | ${2}
+    ${'3'}            | ${'lenny'}        | ${-2}
+    ${'lenny'}        | ${'5'}            | ${0}
+    ${'squeeze'}      | ${'6'}            | ${0}
+    ${'10'}           | ${'buster'}       | ${0}
+    ${'6'}            | ${'squeeze'}      | ${0}
+    ${'buster'}       | ${'10'}           | ${0}
+    ${'oldoldstable'} | ${'8'}            | ${1}
+    ${'oldstable'}    | ${'oldoldstable'} | ${1}
+    ${'stable'}       | ${'oldstable'}    | ${1}
+    ${'11'}           | ${'oldoldstable'} | ${2}
+    ${'10'}           | ${'oldstable'}    | ${0}
+    ${'9'}            | ${'stable'}       | ${-2}
+  `('debian.sortVersions($a, $b) === $expected ', ({ a, b, expected }) => {
+    expect(debian.sortVersions(a, b)).toEqual(expected);
+  });
+
+  it.each`
+    version | range        | expected
+    ${'10'} | ${'10-slim'} | ${false}
+    ${'11'} | ${'11'}      | ${true}
+    ${'11'} | ${'11.0'}    | ${false}
+  `(
+    'matches("$version", "$range") === "$expected"',
+    ({ version, range, expected }) => {
+      expect(debian.matches(version, range)).toBe(expected);
+    }
+  );
+});
diff --git a/lib/modules/versioning/debian/index.ts b/lib/modules/versioning/debian/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d1c9b740ea34068a21f6168b0ee6f173d11bde0a
--- /dev/null
+++ b/lib/modules/versioning/debian/index.ts
@@ -0,0 +1,105 @@
+import type { RangeStrategy } from '../../../types';
+import { DistroInfo } from '../distro';
+import { GenericVersioningApi } from '../generic';
+import type { GenericVersion } from '../generic';
+import type { NewValueConfig, VersioningApi } from '../types';
+import { RollingReleasesData } from './common';
+
+export const id = 'debian';
+export const displayName = 'Debian';
+export const urls = [
+  'https://debian.pages.debian.net/distro-info-data/debian.csv',
+];
+export const supportsRanges = true;
+export const supportedRangeStrategies: RangeStrategy[] = ['pin'];
+
+const RELEASE_PROP = 'release';
+
+export class DebianVersioningApi extends GenericVersioningApi {
+  private readonly _distroInfo: DistroInfo;
+  private readonly _rollingReleases: RollingReleasesData;
+
+  constructor() {
+    super();
+    this._distroInfo = new DistroInfo('data/debian-distro-info.json');
+    this._rollingReleases = new RollingReleasesData(this._distroInfo);
+  }
+
+  override isValid(version: string): boolean {
+    const isValid = super.isValid(version);
+    const schedule = this._distroInfo.getSchedule(
+      this._rollingReleases.getVersionByLts(version)
+    );
+    return (isValid && schedule && RELEASE_PROP in schedule) ?? false;
+  }
+
+  override isStable(version: string): boolean {
+    let ver: string;
+    ver = this._rollingReleases.getVersionByLts(version);
+    ver = this._distroInfo.getVersionByCodename(ver);
+    return this._distroInfo.isReleased(ver) && !this._distroInfo.isEolLts(ver);
+  }
+
+  override getNewValue({
+    currentValue,
+    rangeStrategy,
+    currentVersion,
+    newVersion,
+  }: NewValueConfig): string {
+    if (rangeStrategy === 'pin') {
+      let newVer = newVersion;
+
+      // convert newVersion to semVer
+      if (this._distroInfo.isCodename(newVersion)) {
+        newVer = this._distroInfo.getVersionByCodename(newVersion);
+      }
+      if (this._rollingReleases.has(newVersion)) {
+        newVer = this._rollingReleases.getVersionByLts(newVersion);
+      }
+
+      // current value is codename or [oldold|old|]stable
+      if (
+        this._distroInfo.isCodename(currentValue) ||
+        this._rollingReleases.has(currentValue)
+      ) {
+        return newVer;
+      }
+    }
+
+    // current value is [oldold|old|]stable
+    if (this._rollingReleases.has(currentValue)) {
+      return this._rollingReleases.getLtsByVersion(newVersion);
+    }
+
+    if (this._distroInfo.isCodename(currentValue)) {
+      const di = this._rollingReleases.schedule(newVersion);
+      let ver = newVersion;
+      if (di) {
+        ver = di.version;
+      }
+      return this._distroInfo.getCodenameByVersion(ver);
+    }
+
+    // newVersion is [oldold|old|]stable
+    // current value is numeric
+    if (this._rollingReleases.has(newVersion)) {
+      return this._rollingReleases.schedule(newVersion)?.version ?? newVersion;
+    }
+
+    return this._distroInfo.getVersionByCodename(newVersion);
+  }
+
+  protected override _parse(version: string): GenericVersion | null {
+    let ver: string;
+    ver = this._rollingReleases.getVersionByLts(version);
+    ver = this._distroInfo.getVersionByCodename(ver);
+    if (!this._distroInfo.exists(ver)) {
+      return null;
+    }
+    return { release: ver.split('.').map(Number) };
+  }
+}
+
+export const api: VersioningApi = new DebianVersioningApi();
+
+export default api;
diff --git a/lib/modules/versioning/distro.ts b/lib/modules/versioning/distro.ts
index 7d52f6f3aa5586fcfe625213bec598d71c9d2ecd..bdc90f23eab3c41b513582b7f98f0cd35a040937 100644
--- a/lib/modules/versioning/distro.ts
+++ b/lib/modules/versioning/distro.ts
@@ -1,7 +1,7 @@
 import { DateTime } from 'luxon';
 import dataFiles, { DataFile } from '../../data-files.generated';
 
-interface DistroSchedule {
+export interface DistroSchedule {
   codename: string;
   series: string;
   created: string;
@@ -13,7 +13,9 @@ interface DistroSchedule {
   eol_elts?: string;
 }
 
-export type DistroDataFile = 'data/ubuntu-distro-info.json';
+export type DistroDataFile =
+  | 'data/ubuntu-distro-info.json'
+  | 'data/debian-distro-info.json';
 
 export type DistroInfoRecord = Record<string, DistroSchedule>;
 
@@ -48,7 +50,7 @@ export class DistroInfo {
 
     for (const v of arr) {
       const obj = { version: v, ...this._distroInfo[v.toString()] };
-      if (!obj.eol) {
+      if (!obj.release) {
         // istanbul ignore next
         continue;
       }
diff --git a/package.json b/package.json
index 9ef1a8a55b6bc6023874d9c58edcc91bd1ac9e9b..c8da2617e1054860beb6c84e0863ade4ff490d35 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
     "test-schema": "run-s create-json-schema",
     "tsc": "tsc",
     "type-check": "run-s generate:* \"tsc --noEmit {@}\" --",
-    "update:ubuntu-distro-info": "node tools/distro-json-generate.mjs",
+    "update:distro-info": "node tools/distro-json-generate.mjs",
     "verify": "node tools/verify.mjs"
   },
   "repository": {
diff --git a/tools/distro-json-generate.mjs b/tools/distro-json-generate.mjs
index 4587351f395c098c9672567783093ee796c0d5fc..4459b27cc8a912305f23d26c853bb77cd7f7c098 100644
--- a/tools/distro-json-generate.mjs
+++ b/tools/distro-json-generate.mjs
@@ -2,7 +2,8 @@ import fs from 'fs-extra';
 import got from 'got';
 import shell from 'shelljs';
 
-const url = 'https://debian.pages.debian.net/distro-info-data/ubuntu.csv';
+const ubuntuUrl = 'https://debian.pages.debian.net/distro-info-data/ubuntu.csv';
+const debianUrl = 'https://debian.pages.debian.net/distro-info-data/debian.csv';
 
 /**
  * Converts valid CSV string into JSON.
@@ -73,5 +74,7 @@ async function update(url, file) {
   await updateJsonFile(file, json);
 }
 
-// eslint-disable-next-line @typescript-eslint/no-floating-promises
-update(url, `./data/ubuntu-distro-info.json`);
+(async () => {
+  await update(ubuntuUrl, `./data/ubuntu-distro-info.json`);
+  await update(debianUrl, `./data/debian-distro-info.json`);
+})().catch(() => 'obligatory catch');