PostgreSQL 16 and 17 each added dozens of features. Most of them are developer-facing: new SQL syntax, function improvements, improved type support. The ones that matter to operators are a shorter list — but they change how you observe I/O, configure replication, manage access control, and run backups. Upgrading to PG16 or PG17 without reviewing these operational changes means your dashboards break silently, your replication topology adds unexpected complexity, and your backup process changes in ways your runbooks do not reflect.

Situation

PostgreSQL follows a yearly release cadence. PG16 shipped in September 2023 and PG17 in October 2024. Both releases continue the pattern of adding features that benefit application developers — but they also change or add several infrastructure-level capabilities that operators care about more than developers do.

This post covers only operationally significant changes: new system views, replication topology changes, backup improvements, and access control changes. Developer-facing features (new SQL functions, JSON improvements, etc.) are out of scope.

The Problem

Operators who upgrade without reviewing the release notes typically encounter problems in three categories: monitoring breaks (a metric they relied on moved or changed format), replication complexity increases (a new capability requires opting in or opting out), or a backup workflow changes (new flags or new manifest requirements).

The specific risk with PG16’s pg_stat_io view: if your monitoring stack queries the old I/O metrics from pg_stat_bgwriter and pg_stat_database, those views still exist in PG16, but the granularity and definitions changed. Dashboards built on those views produce misleading numbers without an explicit migration.

The core question for each release: which changes require action before you upgrade, and which require action after?

Core Concept

The operational surface area of PostgreSQL is evolving to provide more granular observability and more flexible replication, while pushing more complexity into backup management.

flowchart TD
    Upgrade[PostgreSQL Upgrade] --> Observability[Observability]
    Upgrade --> Replication[Replication]
    Upgrade --> Backup[Backup and Restore]
    Observability --> IO[Migrate to pg_stat_io]
    Replication --> Lag[Monitor standby logical lag]
    Backup --> Manifest[Manage backup manifests]

PG16 Operational Changes

1. pg_stat_io — new I/O observability view

PG16 introduces pg_stat_io, a new system view that breaks I/O statistics down by backend type (client backend, autovacuum worker, WAL writer, checkpointer, etc.), I/O object (relation, temp relation), and I/O context (normal, vacuum, bulkread). This is the most significant monitoring change in years.

SELECT backend_type, object, context, reads, writes, extends, evictions
FROM pg_stat_io
ORDER BY reads DESC;

Before PG16, I/O was only observable in aggregate via pg_stat_bgwriter and pg_stat_database. After PG16, you can see that autovacuum workers are responsible for 80% of your block reads during a vacuum storm, or that WAL writes are saturating a specific I/O context. If your existing monitoring uses pg_stat_bgwriter.buffers_clean or pg_stat_database.blks_hit, those fields are still present but mean something different from pg_stat_io — do not mix them.

2. Logical replication from standby servers

PG16 allows a physical standby (streaming replica) to act as a logical replication publication source. Before PG16, you could only create a logical replication publication on a primary. With PG16, you can offload the logical decoding CPU and I/O cost to a standby.

This is valuable when logical replication fans out to many subscribers and the decoding overhead affects primary throughput. The tradeoff: if the standby falls behind the primary, logical subscribers reading from the standby see higher replication lag. You now have two lag dimensions to monitor: physical lag (primary → standby) and logical lag (standby → subscriber).

3. Role membership — GRANT ... WITH INHERIT behavior change

PG16 split the previously conflated INHERIT and SET ROLE privileges. Before PG16, GRANT role TO user always implicitly granted both inheritance and the ability to SET ROLE. In PG16, these are separate:

GRANT role TO user WITH INHERIT TRUE;   -- inherits privileges automatically
GRANT role TO user WITH SET TRUE;       -- can SET ROLE to switch to the role

The default behavior did not change for most cases, but explicit GRANT ... WITH INHERIT FALSE statements from before PG16 may behave differently in PG16 if you also relied on SET ROLE.

4. pg_hba.conf and pg_ident.conf now have system views

pg_hba_file_rules and pg_ident_file_mappings are now reliable system views that reflect the actual loaded configuration, including any syntax errors. This replaces the need to parse config files manually for audit purposes.

PG17 Operational Changes

1. Incremental backup with pg_basebackup

PG17 added --incremental support to pg_basebackup. An incremental backup records only the page changes since the last full or incremental backup, using a backup manifest to track which pages changed. The full and incremental backup set must be combined with pg_combinebackup before restore.

# Full backup (save the manifest)
pg_basebackup -D /backup/base --checkpoint=fast

# Incremental backup
pg_basebackup -D /backup/incr1 --incremental=/backup/base/backup_manifest

# Combine before restore
pg_combinebackup /backup/base /backup/incr1 -o /backup/restored

This changes the backup workflow: you will need to store and manage backup manifests, and the restore process requires the combine step. Teams that automate restore testing need to update their scripts before moving to PG17 backups.

2. Vacuum improvements — skip frozen pages

PG17 improved VACUUM’s ability to skip pages that are already fully frozen (all tuples have transaction IDs old enough to be safe). This reduces the I/O footprint of anti-wraparound vacuums on tables with stable old data. No configuration change is needed — this is automatic. The observable effect is shorter elapsed time for VACUUM operations on large tables with significant frozen page counts.

3. Logical replication of sequences (partial)

PG17 added initial sequence replication support. Sequence values can be included in a publication and replicated to a subscriber. This addresses part of the long-standing gap where logical replication subscribers had diverged sequences after promotion. This is an opt-in addition to a publication (FOR ALL SEQUENCES or named sequences) and does not replicate every increment — it sends periodic snapshots of sequence state.

4. MERGE — full support for NOT MATCHED BY SOURCE

PG17 completed the MERGE statement implementation by adding NOT MATCHED BY SOURCE — the ability to delete or update rows in the target that have no matching row in the source, completing the full SQL standard MERGE semantics. This is primarily a developer feature, but it affects ETL pipelines that previously required separate DELETE and MERGE logic.

In Practice

The PostgreSQL 16 release notes (postgresql.org/docs/16/release-16.html) document pg_stat_io as a new view with explicit field definitions. The release notes note that several counters previously in pg_stat_bgwriter are now more granularly available in pg_stat_io, and that pg_stat_bgwriter fields related to buffer I/O are deprecated in favor of pg_stat_io.

The PostgreSQL 17 release documentation (postgresql.org/docs/17/app-pgbasebackup.html) specifies that pg_combinebackup is the required tool for restore — it is not optional. Backup manifests are required inputs for incremental backups and must be retained between backup cycles.

Where It Breaks

ScenarioWhat breaksWhy
Upgrading to PG16 without updating monitoringI/O dashboards show stale or misleading datapg_stat_io changes the metric namespace; old views still exist but have different granularity
Logical replication from standbySubscribers see elevated lag when standby falls behind primaryTwo lag dimensions compound: physical replication lag plus logical decoding lag
PG17 incremental backup without manifest managementRestore fails at pg_combinebackup stepIncremental backups are unusable without the backup manifest from the previous full backup

What to Do Next

  • Problem: Upgrading PostgreSQL without reviewing operational changes breaks monitoring, backup automation, and replication lag calculations without any visible error at upgrade time.
  • Solution: For PG16, migrate I/O monitoring to pg_stat_io before decommissioning old dashboard queries; for PG17, update backup scripts to retain manifests and add a pg_combinebackup step to restore runbooks.
  • Proof: After upgrading to PG16, query pg_stat_io and confirm your monitoring system is capturing backend_type-level I/O breakdown; after upgrading to PG17, execute a test incremental restore and confirm pg_combinebackup completes without error.
  • Action: Before upgrading to either version, grep your monitoring configuration for references to pg_stat_bgwriter.buffers_* and pg_stat_database.blks_* — these are the most commonly broken queries after PG16 adoption.