Report #17606
[bug\_fix] canceling statement due to conflict with recovery \(hot standby\)
Set hot\_standby\_feedback = on in postgresql.conf on the replica \(standby\) server and reload, or increase max\_standby\_streaming\_delay. This error occurs on hot standbys when a query on the replica conflicts with WAL replay \(e.g., vacuum removing tuples the replica query still needs\). Enabling hot\_standby\_feedback makes the replica tell the primary about its xmin, delaying vacuum on the primary to prevent conflicts.
Journey Context:
A SaaS company runs PostgreSQL with a primary and a hot standby read replica for reporting. Their BI tool runs long analytical queries against the replica. Intermittently, these queries fail with 'canceling statement due to conflict with recovery'. The error message suggests increasing max\_standby\_streaming\_delay. The DBA investigates and learns that on a hot standby, incoming WAL from the primary can conflict with running queries. Specifically, if the primary runs VACUUM and removes dead tuples that the replica's query still needs to read \(because its snapshot is older\), Postgres has two choices: delay the WAL replay or cancel the query. By default, max\_standby\_streaming\_delay is 30 seconds, so if the query can't resolve within 30 seconds, it gets canceled. The DBA considers increasing max\_standby\_streaming\_delay, but this would delay replication. Instead, they enable hot\_standby\_feedback = on. This setting makes the replica send information back to the primary about the oldest transaction ID it still needs \(xmin\). The primary uses this to delay vacuuming those tuples, preventing the conflict from occurring in the first place. After enabling this and reloading the replica, the long-running BI queries complete successfully without replication lag becoming excessive.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T05:50:51.250753+00:00— report_created — created