PostgreSQL 17 in Production: What We Changed and What We Left Alone
Why we moved quickly
We upgraded our fleet to PostgreSQL 17 faster than we typically move on major versions — within six weeks of the stable release. The reason was specific: the new MAINTAIN privilege that lets you grant VACUUM and ANALYZE permissions without superuser. For multi-tenant managed hosting, this is a meaningful operational improvement that we wanted for our automated maintenance tooling.
What's noticeably better
Incremental sorting improvements. The planner's ability to leverage partial sort results for ORDER BY on already-partially-sorted data improved query performance on several of the dashboard-style queries our customers run most frequently. We saw 15–30% improvement on queries using window functions over time-series data — without any schema changes.
Logical replication of sequences. Previously, logical replication did not replicate sequence state, which meant failover scenarios could produce duplicate key errors until sequences were manually synchronized. PostgreSQL 17 replicates sequences as part of logical replication. For our migration tooling, this removed an entire class of post-migration checklist items.
Vacuum improvements. The new VACUUM (SKIP_DATABASE_STATS) option lets autovacuum skip the expensive global statistics update when processing individual tables. On databases with hundreds of tables, this meaningfully reduces the overhead of routine maintenance cycles.
What required tuning
The query planner in PostgreSQL 17 is more aggressive about choosing parallel query plans. For most workloads this is good. For a handful of OLTP customers running high-concurrency short queries, the overhead of spawning parallel workers was actually slower than a sequential plan. We added max_parallel_workers_per_gather = 0 to the connection strings of affected applications as a session-level override while we profiled more carefully.
This isn't a regression — it's the planner being smarter about a tradeoff. But it caught us off-guard on three clusters that looked fine in staging and showed latency spikes on the first day of production load.
The gotcha: extension compatibility
One customer was running pg_partman 4.7.x, which had a hard dependency on a function signature that changed in PostgreSQL 17. The extension failed to load after the upgrade, which caused their application's connection pooler to exhaust all connections attempting to reconnect. The application appeared to hang rather than error cleanly.
The fix was straightforward (upgrade to pg_partman 5.x), but the failure mode was surprising. We've since added extension compatibility checks to our pre-upgrade runbook and will not upgrade a cluster to a new major version without verifying all installed extensions against a compatibility matrix.
Our recommendation
If you're running PostgreSQL 16 and not on any unusual extensions, upgrading to 17 is low-risk and worth doing. The incremental sort and vacuum improvements have real impact at scale. If you're using pg_partman, timescaledb, or any custom extensions — test carefully in a staging environment first. We're happy to coordinate upgrades for customers who want our team to handle the process end-to-end.