Bumping Minimum Supported Version for psql/pg_dump/pg_dumpall/pg_upgrade to v10
Core Problem
PostgreSQL's client tools — psql, pg_dump, pg_dumpall, and pg_upgrade — have long maintained backward compatibility with server versions far older than what the project officially supports. Since 2021 (commits 30e7c175b81, e469f0aaf3, cf0cab868a), the floor has been PostgreSQL 9.2. By the v20 development cycle in 2026, that means these tools carry conditional branches for server versions released ~14 years earlier, well beyond the ~10-major-release window that the project has informally adopted as its compatibility horizon.
This accumulated version-specific code manifests as:
- Version-gated SQL in pg_dump: different catalog queries depending on whether
pg_class.relhasoids existed, whether partitioning was available, whether pg_sequence existed (v10), whether relispartition existed, etc.
- Feature-detection branches in psql (
\d family): metadata queries that fan out across versions.
- pg_upgrade-specific code including
rewrite_multixacts() and related MultiXact-era fixups that were needed for the 9.3/9.4 multixact format transition — code Nathan specifically flags as the trickiest part of his patch.
- pg_restore archive-format compatibility: the
K_VERS_* constants, where K_VERS_1_12 was introduced in 2010 for v9.0 and K_VERS_1_13 in 2018 for v11.
The maintenance burden is real: every new catalog change forces authors to reason about a decade-plus of prior schemas, and the old branches can no longer be meaningfully tested because the buildfarm rarely exercises cross-version paths against such old servers. Andrew Dunstan explicitly notes this as a buildfarm pain point — his animals spend cycles running cross-version upgrade tests that are arguably not worth their keep.
Proposed Solution and Scope
Nathan Bossart's proposal is to bump the floor to v10 for v20, aligning with a "past 10 major releases" policy (v20 supporting back to v10). The patch is mostly mechanical removal of version-conditional code paths, followed by reindentation.
Tom Lane's review suggestion is procedurally important: split the patch into (1) the logical removal of conditional branches without reindenting, and (2) a pure pgindent pass. This makes review tractable because outdenting formerly-conditional blocks produces massive diff noise that is indistinguishable from semantic change unless mechanically separated. Nathan agrees and anticipates ~3 patches.
The pg_restore Archive-Version Question
A distinct sub-discussion — more nuanced than the server-version bump — concerns how aggressively to sunset pg_restore's ability to read old custom-format archive files. Tom's reasoning from commit 64f3524e2 is cited directly:
If you have an old server, you probably also have a pg_dump that will work with it; but if you have an old custom-format backup file, that might be all you have.
This asymmetry matters: server compatibility can be worked around by chaining upgrades (Andrew: "people wanting to upgrade from ancient versions can do it in multiple hops"), but a 15-year-old .dump file sitting on tape for compliance/forensic reasons has no "intermediate hop" available if the only tool that could read it has dropped support. Corey Huinker reinforces this framing — the use case is forensic/compliance, not operational.
Nathan's analysis of the version constants:
K_VERS_1_12 — added 2010 for v9.0. Well outside the 10-release window.
K_VERS_1_13 — added 2018 for v11. Inside the 10-release window for v20.
He proposes that K_VERS_1_12 is the latest archive format the floor could be raised to, and floats a separate policy of "past 15 major releases for pg_restore", acknowledging the archive-file asymmetry. Tom pushes further: the real payoff isn't just removing K_VERS_x-gated code (of which there isn't much) but rather removing TOC entry types we no longer generate and workarounds for bugs we no longer have. He suggests using the code coverage report to identify unexercised pg_restore stanzas as a starting point.
Documentation / User-Facing Recourse
Corey proposes a documentation table mapping each PostgreSQL version to:
- the highest version a live database can be
pg_upgrade'd to, and
- the highest version a dumpfile can be
pg_restore'd into.
Optionally paired with a script to "re-dump an old dumpfile to a newer dump version" — effectively a dump-format transcoder. Tom extends this by pointing out that server-side changes also break dump/restore compatibility, citing v13 commits e58a59975, 84eca14bc, bb03010b9 as examples. This means the upgrade-path matrix is not purely a function of client-tool version support; it must also account for semantic changes in what dumps mean across server versions.
Cadence and Policy
Andrew's explicit endorsement — "5 years since the last time we did this, and that seems about the right interval" — with Corey agreeing, effectively sets an informal cadence. This is important because it signals the project isn't moving toward an annual drop policy; the bar for bumping is high enough that tool authors should still expect to write code that works across ~10 releases at any given time.
Technical Implications for the pg_upgrade Patch
Nathan's final message (May 1) flags rewrite_multixacts() as the uncertain piece. This function exists to handle the MultiXact on-disk format transition that occurred in the 9.3/9.4 era — specifically because old multixact members files needed to be rewritten or interpreted differently. Once v10 is the floor, all source clusters have the post-transition format, and the rewrite logic can be removed or drastically simplified. The care here is warranted because getting MultiXact handling wrong in pg_upgrade can silently corrupt clog/multixact state in the upgraded cluster.
Synthesis
The thread represents a routine but consequential maintenance action with two distinct technical axes:
- Server version floor (straightforward): remove conditional code for pre-v10 servers. The main risks are in pg_upgrade's multixact handling and the review difficulty of large reindent diffs.
- Archive format floor (subtle): more conservative treatment warranted because archive files outlive servers. The discussion converges on keeping pg_restore more permissive than pg_dump, and attacking dead code via coverage analysis rather than just
K_VERS_x grep.
The user-facing mitigation — a documented upgrade-path matrix plus possibly a dump-transcoding utility — is the right ergonomic answer to "we're dropping support for your 9.2 dump file."