PostgreSQL 19: REPACK, WAIT, and a planner you can finally argue with

PostgreSQL 19 merges VACUUM FULL and CLUSTER into REPACK, adds a WAIT command for catching a standby up, and ships two extensions that pin planner decisions. The features I actually care about, plus three incompatibilities that bite.

PostgreSQL 19’s documentation is still rolling (the release notes still show the date as pending), but the overview has settled. A few entries that will genuinely change day-to-day operations:

REPACK: VACUUM FULL and CLUSTER in one command

Reclaiming disk space meant VACUUM FULL; rewriting a table in index order meant CLUSTER. Both take an exclusive lock. 19 merges them into a single REPACK, and adds a CONCURRENTLY option that reorganises without blocking reads or writes.

The point is not the shorter syntax. It is that reorganising a large table moves from requires downtime to schedule it whenever. Rewriting a few-hundred-gigabyte table used to mean announcing a maintenance window.

WAIT: read your own writes on a replica

Primary/replica setups have always had an awkward edge: write to the primary, immediately read a replica, and the row may not be there. The new WAIT command blocks until a standby has replayed changes up to a chosen point — read-your-writes, on the standby.

That beats “sleep 200ms and retry” by a wide margin, and it is cheaper than routing every read to the primary.

The planner can be pinned

Two new extensions: pg_plan_advice stabilises and controls the query planner’s decisions, and pg_stash_advice applies that advice automatically based on the query.

Plan drift is an old wound — the same SQL runs fine yesterday, statistics update overnight, and today it picks a catastrophic plan. The previous answers were third-party extensions like pg_hint_plan or rewriting the SQL. Now the core ships an official mechanism.

Replication and vacuuming

  • Logical replication now replicates sequence values, and can be enabled without a server restart when wal_level is replica
  • Autovacuum can use parallel workers to vacuum a table’s indexes, with a new scoring system deciding which tables most need it
  • The number of I/O worker processes scales automatically, and foreign-key checks are faster

The “no restart” part matters more than it sounds. Enabling logical replication used to mean changing wal_level and restarting — on a busy primary, that is a scheduled event.

Three incompatibilities that bite

Know these before upgrading:

  1. RADIUS support removed. The stated reason is blunt: it only supported RADIUS over UDP, which is “unfixably insecure”. If your auth chain uses RADIUS, plan a replacement.
  2. standard_conforming_strings is forced on in the server. Dumps produced by pre-19 pg_dump/pg_dumpall with standard_conforming_strings = off will not load correctly into 19 and later. Dump with 19+ tooling.
  3. Carriage returns and line feeds are disallowed in database, role, and tablespace names. pg_upgrade checks for this.

Two smaller ones: a new password_expiration_warning_threshold (default seven days), and a warning after successful MD5 password authentication, disableable via md5_password_warnings. MD5 passwords were marked deprecated back in 18.

Where I land

Of the four headline items, REPACK ... CONCURRENTLY and WAIT change how you operate. The planner-advice extensions are a receipt for something people had been bolting on for years.

The real risk is in the compatibility list. RADIUS was removed because it is insecure — and PostgreSQL has consistently been more willing than most projects to delete a feature for correctness. If RADIUS sits anywhere in your auth path, this upgrade is not a “someday” item.

← Back to all posts

Comments

…