Keycloak 26.7 needs PostgreSQL 13. Keycloak 26.0 didn't.

Keycloak 26.0.0 runs on PostgreSQL 12. Keycloak 26.7.1 refuses to. The minimum supported Postgres major moved from 12 to 13 inside major version 26 — across what looks, from the version number, like a routine minor bump.

We installed Keycloak 26.0.0 on Postgres 12.22, seeded a realm, and upgraded to 26.7.1. It stopped before it started:

ERROR: Persistence unit 'keycloak-default' was configured to run with a database version of at least '13.0.0', but the actual version is '12.22.0'.

The floors we measured, on the official image with start against an external database (single node, 202 users, 2 realms, Hetzner CCX33, JVM -Xms1g -Xmx4g):

KeycloakMinimum Postgres major
26.0.012
26.7.113

On Postgres 13.23 the same upgrade took sixteen seconds and worked perfectly. The floors are real and they moved a whole database major within one Keycloak major.

The refusal is clean — the fix is not

The good news is that it fails closed. After 26.7.1 refused to start on Postgres 12.22, the changelog was still at 144 rows, migration_model still read 26.0.0, all 202 users were intact, and the container exited 1. Nothing was half-applied; rolling back means putting the old image tag back.

The bad news is what the fix is. You cannot resolve this inside the Keycloak change window. It needs a database major upgrade — a different project, a different risk profile, and usually a different team. If you discovered it during the window, the window is over.

That is why this one sits at the top of the pre-flight. It is the first thing that can end a window. Nearly every other failure this lab has produced can be fixed inside one. This cannot.

The escape hatch, and why we did not test it

Both versions offer an override, and they do not name the same property:

Refusing versionSuggested override
26.7.1 on PG 12jakarta.persistence.database-product-version=12.22.0
26.0.0 on PG 11quarkus.datasource.db-version=11.16.0

Both append the same warning: "this may disable some features and/or impact performance negatively". We deliberately did not test either. It is a documented way to start on an unsupported database, and it is unsupported all the same. A rescue engagement should treat it as a bridge to a database upgrade.

The pre-flight question nobody asks

The Keycloak version number does not suggest this needs asking. Ask it anyway:

select version();

Two things we could not establish:

  • Which 26.x release moved the floor. It is only known to be somewhere in (26.0.0, 26.7.1]. A shop planning a hop to any specific 26.x should check that release's requirements directly — the floor evidently moves, so any single measurement expires.
  • The documented matrix — checked, partially. We cross-checked against Keycloak's live supported-database matrix. It now lists PostgreSQL 14.x through 18.x as supported (tested version 18). That is a later Keycloak than the 26.x line we measured, and a floor that has kept climbing past the 13 we recorded. It confirms the direction of the finding: the floor only moves up, including inside a major. The specific 26.0.0 / 26.7.1 floors resisted re-verification against archived 26.x release notes, so treat those two numbers as measured and the direction as confirmed.

A stranded Keycloak usually sits on a stranded database. The customers who most need an upgrade are the ones who deferred everything, and Postgres was on the same deferral list. Scope the engagement as two upgrades, sequenced — and check the database floor first.

Keycloak Advisory Watch — one email per advisory batch, within 72 hours of publication, listing the patched versions per maintained minor line. Double opt-in, no tracking pixels, no click tracking, public archive. Subscribe.

Self-hosted Keycloak is one of the things we keep patched, upgraded and owned for teams that run it but have nobody to run it. Talk to us about your project.

Source: 2026-08-25-s12-postgres-major-floor. Unchecked rows from the record carried here as open items: the exact 26.x release that raised the floor, the override flags, and managed-service equivalents (RDS / Cloud SQL / Azure).

Next
Next

By 2029 every public TLS certificate renews 7.77 times a year, and a calendar can't keep up