Safeguard
Vulnerability Management•

PostgreSQL 14 End of Life on 12 November 2026: What 2026 Fixed and How to Upgrade

PostgreSQL 14's final release is due on 12 November 2026. This year it needed fixes for 36 CVEs, 22 rated 8.0 or higher. The community and Amazon RDS dates that apply, two security defaults a 14-to-18 upgrade doesn't change for you, and a script that finds every pinned PostgreSQL version in a repository.

Safeguard Security Team
Security Research
11 min read

PostgreSQL 14 gets its last release on 12 November 2026. After that, the PostgreSQL project stops fixing it, and 2026 shows what that means: this year's three quarterly releases fixed 36 CVEs that affect 14, 22 of them rated 8.0 or higher. The next bug found in code that 14 shares with newer versions will be fixed in 15 to 18 and left open in 14.

This post is for teams running PostgreSQL 14 on their own servers, in containers or on a managed service. It covers the dates that apply to you, what 2026's security releases fixed, two upgrade changes that affect security settings, and a script that finds every place a repository pins a PostgreSQL version.

The short answer

PostgreSQL 14's final minor release is scheduled for 12 November 2026, the project's next quarterly release date. In 2026, PostgreSQL 14 received fixes for 36 CVEs: 4 in 14.21 (12 February), 8 in 14.23 (14 May) and 24 in 14.24 (13 August), 22 of them rated CVSS 8.0 or higher. After 12 November, new vulnerabilities in 14 stay unfixed upstream. Amazon RDS keeps PostgreSQL 14 in standard support until 28 February 2027 and offers paid Extended Support after that, but minor versions 14.18 and 14.19 leave RDS standard support on 31 October 2026. Plan a major upgrade to PostgreSQL 18, supported until November 2030, and review two defaults the jump changes: CREATE on the public schema and MD5 passwords.

The dates that apply to you

WhatDateSource
PostgreSQL 14 final release (community end of life)12 November 2026postgresql.org versioning policy and roadmap
Last scheduled minor releases for 1413 August 2026 (14.24) and 12 November 2026postgresql.org release notes and roadmap
Amazon RDS: 14.18 and 14.19 leave standard support31 October 2026RDS for PostgreSQL release calendar
Amazon RDS: PostgreSQL 14 end of standard support28 February 2027RDS release calendar
Amazon RDS: Extended Support for 14 (paid)1 March 2027 to 28 February 2030RDS release calendar
PostgreSQL 15 end of life11 November 2027postgresql.org versioning policy
PostgreSQL 18 end of life14 November 2030postgresql.org versioning policy

Other managed services publish their own calendars. Check yours, since a provider's extended support usually means the provider backports fixes, not the PostgreSQL project.

Upgrading to 15 buys one year. Upgrading to 18 buys four, and pg_upgrade supports going from 14 straight to 18.

What 2026's security releases fixed in 14

We read PostgreSQL's security page and counted the CVEs it lists as affecting version 14, grouped by the 14.x release that fixed them:

ReleaseDateCVEs affecting 14CVSS 8.0 or higherComponent
14.2112 February 202643core server 2, contrib 2
14.2314 May 202684core server 5, client 2, contrib 1
14.2413 August 20262415core server 15, client 4, contrib 5

Most of the high scores need a logged-in database user (PR:L in the vectors), so the realistic threat is an application account, a reporting user or a compromised service turning into code execution as the database server. A few need no login at all, such as CVE-2026-6479, a denial of service during SSL or GSS connection setup fixed in 14.23. The client-side ones matter too: in 14.24, CVE-2026-19385 is a heap buffer overflow in pg_dump, and CVE-2026-18408 lets the superuser of the server you dumped from run code in the psql that restores the dump.

Not every new bug reaches 14. Eight 2026 CVEs on the page affect only newer versions, because they're in features 14 doesn't have. But most of 2026's bugs were in code all five supported versions share, and that's the code that stops getting fixes for 14.

Two upgrade changes that touch security

Major upgrades from 14 to 18 change several defaults. Two are security settings, and one of them doesn't change by itself.

CREATE on the public schema. PostgreSQL 15 removed the default CREATE permission for PUBLIC on the public schema, which is the secure pattern recommended since CVE-2018-1058. The release notes say this applies to new clusters and new databases, and that upgrading with pg_upgrade or restoring a dump keeps the old permissions. So an upgraded database still lets every role create objects in public. Check and fix it after the upgrade:

-- true means every role can still create objects in the public schema
SELECT has_schema_privilege('public', 'public', 'CREATE');

-- adopt the PostgreSQL 15+ default (grant CREATE back to the roles that need it)
REVOKE CREATE ON SCHEMA public FROM PUBLIC;

MD5 passwords. PostgreSQL 18 deprecates MD5 password authentication and warns when you set an MD5 password. Support will be removed in a future major version. It's worth moving to SCRAM before you need to: 14.23 fixed CVE-2026-6478, which disclosed MD5-hashed passwords through a timing side channel.

-- roles that still have MD5-hashed passwords (needs superuser)
SELECT rolname FROM pg_authid WHERE rolpassword LIKE 'md5%';

-- 14 already defaults to SCRAM; this undoes an old config that set md5
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();

Each listed role then needs its password set again, and pg_hba.conf lines that say md5 can move to scram-sha-256 once every client supports it. We didn't run these SQL snippets against a server for this post. They use standard functions and catalogs documented for all supported versions.

One more note from the pg_upgrade documentation: upgrading a cluster lets the source cluster's superusers execute arbitrary code in the destination. Upgrade from a cluster you trust, and don't treat an upgrade as a way to clean up a compromised one.

Find every pinned PostgreSQL version

Database versions hide in Dockerfiles, Compose files, Helm values, Terraform and CI service containers, and the one in production isn't always the one in the repository. This script walks a repository, finds pinned PostgreSQL major versions in those files and marks each as past end of life, within 180 days of it, or supported. It uses only the Python standard library and exits with status 1 if anything is past or within 180 days of end of life:

#!/usr/bin/env python3
"""Find PostgreSQL major versions pinned in a repository and flag the ones at
or near community end of life. Looks at Dockerfiles, Compose and Kubernetes
YAML, Helm values, Terraform and CI files.

Usage: python3 pg_eol_scan.py [repo_dir]"""
import datetime as dt
import os
import re
import sys

# Final release dates from postgresql.org/support/versioning (October 2026)
EOL = {
    11: dt.date(2023, 11, 9), 12: dt.date(2024, 11, 21), 13: dt.date(2025, 11, 13),
    14: dt.date(2026, 11, 12), 15: dt.date(2027, 11, 11), 16: dt.date(2028, 11, 9),
    17: dt.date(2029, 11, 8), 18: dt.date(2030, 11, 14),
}
PATTERNS = [
    # image: postgres:14.24-alpine, FROM postgres:14, bitnami/postgresql:14.13.0
    re.compile(r"(?:^|[\s\"'/=])(?:postgres|postgresql|postgis/postgis)"
               r":(?P<v>\d{1,2})(?:[.\-][\w.\-]*)?(?=[\s\"']|$)"),
    # Terraform: engine_version = "14.24" (aws_db_instance, aws_rds_cluster)
    re.compile(r"engine_version\s*=\s*\"(?P<v>\d{1,2})(?:\.\d+)?\""),
    # Cloud SQL: database_version = "POSTGRES_14"
    re.compile(r"database_version\s*=\s*\"POSTGRES_(?P<v>\d{1,2})\""),
    # Helm/values or CI: postgresqlVersion: 14, postgres-version: "14"
    re.compile(r"(?i)postgres(?:ql)?[_-]?version[\"']?\s*[:=]\s*[\"']?(?P<v>\d{1,2})\b"),
]
# Helm values with the image split into repository: and tag: lines
TAG = re.compile(r"^\s*tag:\s*[\"']?(?P<v>\d{1,2})\.")
SUFFIXES = (".yml", ".yaml", ".tf", ".json", ".toml", ".env")
NAMES = ("Dockerfile", "Containerfile")


def scan(root, today):
    hits = []
    for dirpath, dirs, files in os.walk(root):
        dirs[:] = [d for d in dirs if d not in (".git", "node_modules", ".terraform")]
        for name in files:
            if not (name.endswith(SUFFIXES) or name.startswith(NAMES)):
                continue
            path = os.path.join(dirpath, name)
            with open(path, encoding="utf-8", errors="replace") as f:
                recent = []
                for n, line in enumerate(f, 1):
                    m = TAG.match(line)
                    if m and any("postgres" in r for r in recent):
                        major = int(m.group("v"))
                        if major in EOL:
                            hits.append((path, n, major, line.strip()))
                    recent = (recent + [line.lower()])[-3:]
                    for pat in PATTERNS:
                        for m in pat.finditer(line):
                            major = int(m.group("v"))
                            if major in EOL:
                                hits.append((path, n, major, line.strip()))
    for path, n, major, line in hits:
        days = (EOL[major] - today).days
        if days < 0:
            status = f"PAST EOL since {EOL[major]}"
        elif days <= 180:
            status = f"EOL {EOL[major]} ({days} days)"
        else:
            status = f"supported until {EOL[major]}"
        print(f"{status:32} {os.path.relpath(path, root)}:{n}  {line}")
    return any(EOL[m] <= today + dt.timedelta(days=180) for _, _, m, _ in hits)


if __name__ == "__main__":
    root = sys.argv[1] if len(sys.argv) > 1 else "."
    sys.exit(1 if scan(root, dt.date.today()) else 0)

On a sample repository with a Compose file, a migration Dockerfile, Helm values and Terraform:

EOL 2026-11-12 (24 days)         infra/rds.tf:3  engine_version = "14.19"
supported until 2028-11-09       infra/rds.tf:6  database_version = "POSTGRES_16"
PAST EOL since 2025-11-13        deploy/Dockerfile.migrate:1  FROM postgres:13
EOL 2026-11-12 (24 days)         deploy/docker-compose.yml:3  image: postgres:14.24-alpine
supported until 2029-11-08       deploy/docker-compose.yml:5  image: "postgres:17"
EOL 2026-11-12 (24 days)         deploy/values.yaml:4  tag: 14.13.0

The Terraform line pins 14.19 on RDS, which leaves RDS standard support on 31 October, before the community end of life. The migration image runs PostgreSQL 13, already a year past end of life, which is easy to miss because it only runs during deploys. The script reads what's written in the repository. For what's actually running, SELECT version(); on each server is the source of truth. The EOL table stops at 18, the newest major on the versioning page on 19 October, and the script skips majors it doesn't know. PostgreSQL 19 reached its first release candidate on 15 October, so add it to the table once the versioning page lists its end-of-life date.

Container images are where old database versions linger longest. Here's Safeguard's interactive walkthrough of scanning a container image:

What to do

  1. Inventory every PostgreSQL 14 instance, including CI service containers, migration and backup jobs, and read replicas, with the script above and SELECT version();.
  2. Apply 14.24 now and the final release when it ships. Neither ends the need to upgrade, but 14.24 fixes 24 CVEs.
  3. On RDS, move off 14.18 and 14.19 before 31 October, then plan the major upgrade before 28 February 2027 unless you've budgeted for Extended Support.
  4. Upgrade to 18, testing with pg_upgrade --check first, or use logical replication to a new cluster if you need near-zero downtime.
  5. After the upgrade, revoke CREATE on public from PUBLIC and move MD5 passwords to SCRAM. Neither happens automatically. Our post on the PostgreSQL CVE-2025-1094 response shows how quickly a PostgreSQL bug can turn into something attackers use.

The fair view

Five years of support is generous, and PostgreSQL announces its dates years in advance and sticks to them. Running 14 for a few weeks past 12 November won't suddenly break anything, and managed providers' extended support is a real option for teams that need more time. Major upgrades of large databases are hard to schedule, and a rushed one causes outages of its own.

The cost of waiting is cumulative, though. In 2026 alone, 36 CVEs needed a fix in 14. From 13 November, the next one won't get one upstream, and every month after that adds to the list of known, unfixed bugs on that server. A database upgraded in a planned window this quarter is cheaper than one upgraded in a hurry after the first bad CVE of 2027.

Check yourself

You upgraded from 14 to 18 with pg_upgrade. Can any role still create tables in the public schema?

Yes, probably. PostgreSQL 15 changed the default only for new clusters and new databases. pg_upgrade and dump restores keep the old permissions, so run SELECT has_schema_privilege('public', 'public', 'CREATE'); and revoke it if the answer is true.

Your RDS instance runs PostgreSQL 14.19. Which date comes first?

31 October 2026, when RDS ends standard support for minor versions 14.18 and 14.19. The community end of life for 14 follows on 12 November, and RDS standard support for major version 14 ends on 28 February 2027.

Why does a client-side CVE like the pg_dump overflow matter for a database upgrade?

Upgrades and migrations usually involve dumping and restoring, or connecting tools to servers you don't fully control. 14.24 fixed a heap buffer overflow in pg_dump and a way for a source server's superuser to run code in the psql restoring its dump, so use patched client tools for the migration itself.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.