Guide
September 28, 2026
8 min read
Maxime Dalessandro

Postgres 14 end of life: the jump is four majors wide

Community support for Postgres 14 ends this November. Leaving it means crossing every incompatibility that 15, 16, 17 and 18 shipped, in one maintenance window.

#PostgreSQL#Postgres 14#end of life#pg_upgrade#database migration#upgrade guide

TL;DR. PostgreSQL 14 stops receiving fixes this November. The upgrade off it is not one step but four: a team leaving 14 crosses everything 15, 16, 17 and 18 changed, on a single maintenance window. The removals and renames are the cheap part, because they fail loudly in staging. The expensive part is the set of changes that do not error: a public schema that new databases lock down, maintenance operations that stopped trusting your search_path, a checksum default that can refuse the upgrade itself, and, on any target except 18, a new cluster that starts with no optimizer statistics at all. Land on 18: it is supported a year longer than 17, and it is the only target that carries your planner statistics across.

The PostgreSQL project supports each major version for five years, ships one final minor release, and then stops fixing it. That is the whole of what end of life means, and for Postgres 14 it arrives now: "PostgreSQL 14 will stop receiving fixes on November 12, 2026. If you are running PostgreSQL 14 in a production environment, we suggest that you make plans to upgrade to a newer, supported version of PostgreSQL," as the project has put it in its minor-release announcements all year.

The existing pages about this deadline are mostly date tables and extended-support pitches. What they skip is the shape of the work. Nobody leaving 14 upgrades to 15; the sensible targets are 17 or 18, which means the migration crosses three or four majors of accumulated release notes at once. Each of those majors was, on its own, a modest upgrade. Stacked, they sort into two piles that deserve opposite amounts of your attention: changes that error, and changes that just start being true.

Support runway from late September 2026 for PostgreSQL 14 through 18. Version 14's bar ends almost immediately at November 12, 2026, while each later major extends roughly one year further, out to November 2030 for version 18. An arc marks the single pg_upgrade jump from 14 to 18 across the four rows.

The loud pile is the cheap one

A four-major jump collects an intimidating list of removals, and almost none of them deserve fear, because every one of them fails fast and unambiguously the first time you exercise it against the new version.

From 15: the long-deprecated exclusive backup mode is gone, and pg_start_backup() / pg_stop_backup() are now pg_backup_start() / pg_backup_stop(), so backup scripts written against 14 break on first run. PL/Python's plpythonu and plpython2u are gone with Python 2 itself. The statistics collector process no longer exists, its data lives in shared memory now, and the stats_temp_directory setting was removed with it.

From 16: promote_trigger_file and vacuum_defer_cleanup_age are removed, force_parallel_mode is renamed to debug_parallel_query, and CREATEROLE lost most of its reach. A role with CREATEROLE can no longer hand out attributes like REPLICATION or BYPASSRLS without holding admin option on the target role, which breaks provisioning scripts that assumed 14's looser behavior.

From 17: old_snapshot_threshold is removed, so is the adminpack extension, and pg_stat_statements renamed its I/O timing columns, blk_read_time to shared_blk_read_time and blk_write_time to shared_blk_write_time. Every dashboard and alert built on those column names stops at the first query against the upgraded catalog.

All of this is findable with a grep over your configuration management, your monitoring queries and your operational scripts, plus one full pass of the application test suite against the target version. Budget a week of mechanical work and move on. The pile that deserves the calendar time is the other one.

The quiet pile is where upgrades go wrong

Four changes in the stack do not announce themselves, and each one surfaces at a different distance from upgrade day.

The public schema closed. Since 15, CREATE permission on the public schema is revoked from PUBLIC, and the schema is owned by pg_database_owner rather than the bootstrap superuser. The subtlety is the scope: the release notes are explicit that existing databases keep their current permissions through an upgrade, while newly created databases get the locked-down default. So the upgraded cluster behaves exactly as before, for months, until someone creates a fresh database and an application role that has always been able to CREATE TABLE suddenly cannot. The failure arrives long after anyone is watching the upgrade.

Maintenance stopped trusting your search_path. Since 17, ANALYZE, REINDEX, CLUSTER, VACUUM, CREATE INDEX and materialized-view refreshes run functions under a safe search_path. A function used by an expression index that resolves names through a non-default schema, and that never declared its own search path, has worked for years on 14. On the upgraded cluster it works too, right up until the first REINDEX or autovacuum-triggered ANALYZE touches that index, and the maintenance operation itself fails. The fix is to pin search_path on those functions at creation, which you can do before the upgrade, on 14, today.

Recursion flipped in 18. VACUUM and ANALYZE on a parent table now process its inheritance children by default; the old behavior needs the new ONLY keyword. Maintenance scripts written for 14's semantics keep running without an error and simply do different, larger work. If your vacuum scheduling is tuned per partition-like inheritance trees, the runtime and lock profile of existing jobs changes underneath the same command text. Given how easily index maintenance debt compounds when vacuum behavior shifts, this one earns a read of every scheduled VACUUM and ANALYZE you run.

Session semantics moved. Since 17, SET SESSION AUTHORIZATION decides based on the session user's superuser status at the time the command runs, not at connection time. Connection poolers and privilege-juggling middleware built around the old rule keep functioning, they just authorize differently in edge cases, which is precisely the kind of behavioral drift no test suite catches unless someone wrote a test for the old rule on purpose.

This pile is the reason a 14 exit wants a real staging soak, with production-shaped workload and production-shaped maintenance windows, rather than a smoke test. It is the same lesson DDL keeps teaching: the statements that look identical are the ones that hide the divergence, the way one word in an ADD COLUMN separates a metadata change from a full table rewrite.

pg_upgrade across four majors

The tool itself is the least of the problems. pg_upgrade supports source clusters back to 9.2, so 14 to 18 is one run, and 18's version can process its pre-flight database checks in parallel under --jobs. Three mechanics matter at this width.

Transfer mode decides your rollback story. Default copy leaves the old cluster intact but doubles disk and takes hours on large clusters. --link hard-links files and is nearly instant, at the price that the old cluster is unsafe to start once the new one has run. --clone gets link-like speed with the old cluster left untouched, where the filesystem supports reflinks. 18 adds --swap, which moves the data directories outright and is "potentially the fastest", but destructively modifies the old cluster from the moment transfer begins. On a four-major jump, where the surprise surface is at its widest, mode choice is really a decision about whether you keep a bootable 14 to fall back to.

Checksums can veto the upgrade at initdb. 18 changed the initdb default to enable data checksums, and pg_upgrade requires the two clusters' checksum settings to match. A 14 cluster initialized with the old default, checksums off, meets a new 18 cluster initialized with the new default, checksums on, and pg_upgrade refuses. Either initialize the target with --no-data-checksums and keep your old setting, or bring the 14 cluster up to checksums first with pg_checksums, which runs only against a cleanly shut down cluster and rewrites every block that needs it, so on a large cluster it is its own maintenance window, not a checkbox.

Statistics decide how the first hour goes. Through 17, pg_upgrade transfers no optimizer statistics: the new cluster opens with every table unanalyzed, and the planner guesses until vacuumdb --all --analyze-in-stages has walked the estate. That gap, production traffic against a statistics-free planner, is where post-upgrade incident stories come from. 18 is the first release whose pg_upgrade preserves most optimizer statistics, with extended statistics the notable exception, and the remaining post-upgrade work shrinks to filling the gaps. This, more than any headline feature, is the argument for landing on 18 rather than 17.

Choosing the landing version

The support windows do the arithmetic for you: 15 is supported through November 2027, 16 through November 2028, 17 through November 2029, and 18 through November 2030. Landing on 15 or 16 buys one or two years before the same project starts again, which is why the real choice is 17 versus 18, and 18 wins on both the extra year and the statistics preservation above. The counterweight is your extension list: every extension, and the exact versions of it, must exist for the target major, and that check belongs at the top of the plan, not the bottom.

What 18 asks in exchange is planner and I/O behavior that has moved four majors' distance from what your workload was tuned against. Asynchronous I/O changes how sequential scans, bitmap heap scans and vacuum read data; btree skip scan makes multicolumn indexes usable by queries that previously ignored them, which means new plans for old queries. None of that is a reason to stay, all of it is a reason to treat the soak as a plan-comparison exercise rather than a pass-fail test. The tooling direction here is encouraging: Postgres 19's REPACK and plan advice work is explicitly built for that kind of automated before-and-after, but for a 14 exit this fall, the comparison discipline is yours to run.

Where Datapace fits

A four-major jump is, before anything else, an inventory problem: which roles assume the old CREATEROLE, which functions feed expression indexes without a pinned search_path, which scripts still call pg_start_backup(), which dashboards read columns 17 renamed. Datapace is building the context layer between your databases and your AI: resolved meaning about the estate, validated by the people who own it, with the workload evidence beside it, served to agents over MCP with a policy gate on what they may do. An upgrade like this is exactly when that inventory pays for itself, because the version you are leaving is the last one that will ever patch whatever you forgot. If you want the enforcement side of that story, start with how we think about agents and production databases, or book a call.

Sources

  1. PostgreSQL, Versioning Policy (five-year support policy, final minor release, and the end-of-life dates for versions 14 through 18).
  2. PostgreSQL, PostgreSQL 18.4, 17.10, 16.14, 15.18, and 14.23 Released!, May 14, 2026 (the project's upgrade advisory wording for the 14 line).
  3. PostgreSQL, Release 15 notes (public schema permission and ownership change and its scope, exclusive backup removal and function renames, statistics collector removal, PL/Python changes).
  4. PostgreSQL, Release 16 notes (removed server variables, CREATEROLE restrictions, force_parallel_mode rename).
  5. PostgreSQL, Release 17 notes (old_snapshot_threshold and adminpack removal, safe search_path for maintenance operations, pg_stat_statements column renames, SET SESSION AUTHORIZATION change).
  6. PostgreSQL, Release 18 notes (data checksums enabled by default in initdb, pg_upgrade checksum matching and statistics preservation, --swap, parallel checks, asynchronous I/O, btree skip scan, VACUUM/ANALYZE inheritance change).
  7. PostgreSQL Documentation, pg_upgrade (supported source versions, transfer modes and their caveats, post-upgrade vacuumdb sequence).
  8. PostgreSQL Documentation, pg_checksums (offline requirement, in-place block rewrite, duration caveat).

Frequently asked questions

When is Postgres 14 end of life?
November 12, 2026. PostgreSQL majors get five years of support; the project ships a final minor release on that date and then stops issuing bug and security fixes for the 14 line entirely.
Can pg_upgrade go directly from Postgres 14 to 18?
Yes. pg_upgrade supports source clusters back to 9.2, so a single run can cross 14 to 18. The old and new clusters must agree on data checksum settings, and extension compatibility is on you to verify first.
Why does pg_upgrade to Postgres 18 fail with a checksum mismatch?
PostgreSQL 18 changed the initdb default to enable data checksums, and pg_upgrade requires matching checksum settings. Initialize the new cluster with --no-data-checksums, or enable checksums on the old cluster offline with pg_checksums first.
Do I need to run ANALYZE after upgrading Postgres with pg_upgrade?
Landing on 17 or earlier, yes: no optimizer statistics carry over, so run vacuumdb --all --analyze-in-stages before opening traffic. Landing on 18, most statistics transfer; run the --missing-stats-only pass to fill the gaps, then an analyze-only pass.
Should I upgrade Postgres 14 to 17 or to 18?
18, unless an extension you depend on says otherwise. It is supported a year longer, through November 2030, and an upgrade onto it opens with a warm planner instead of a statistics-free one, which removes the worst day-one performance risk of the jump.

Keep reading

Ready to let agents touch production, safely?

Bring a use case. We will show you what agents can do on your live data, inside your guardrails.