ArmorDB Logo
ArmorDB
Fix Postgresql Conflict With Recovery
Fix PostgreSQL Canceling Statement Due to Conflict With Recovery
Back to Blog
Short-Form & Quick Fixes
July 7, 2026
5 min read

Fix PostgreSQL Canceling Statement Due to Conflict With Recovery

Learn why standby queries can be canceled by PostgreSQL recovery conflicts, how to diagnose the cause, and what to change safely in managed PostgreSQL.

AE
ArmorDB EngineeringArmorDB engineering
PostgreSQLReplicationRead Replicas

The PostgreSQL error canceling statement due to conflict with recovery usually appears on a read replica, not on the primary database. The query may be perfectly valid. PostgreSQL cancels it because the standby has to keep replaying write-ahead log records from the primary, and the query is holding onto a snapshot or resource that blocks that recovery work.

The fastest fix is to identify whether the query belongs on the replica at all, then either shorten the query, route it to the primary, or tune standby-conflict behavior deliberately. Raising delays without understanding the workload can make replicas stale, while ignoring the error can break dashboards, analytics jobs, and read-after-write paths in production.

Why this error happens

A PostgreSQL standby is not just a second server answering reads. In physical streaming replication, it continuously receives and replays WAL from the primary. That replay may need to remove dead row versions, apply DDL, drop files, or take locks that are incompatible with a query currently running on the standby. When the standby cannot both keep replaying recovery and let the query continue, PostgreSQL eventually cancels the query.

The official hot standby documentation calls these standby query conflicts. They can be caused by locks, dropped tablespaces, dropped databases, vacuum cleanup, buffer pin conflicts, or deadlocks detected while replaying WAL. The user-facing message often looks the same at first glance, so the useful diagnosis is not just "the replica is broken." It is "which recovery operation did this read block, and is the read allowed to lag recovery?"

This is most visible on replicas used for reporting, admin queries, or expensive API reads. A query that scans many rows can keep an old snapshot alive. Meanwhile, the primary keeps updating and vacuuming. The standby cannot retain every old row version forever, so it chooses between canceling the read and falling behind the primary.

Quick diagnosis

Start by confirming that the failing connection is pointed at a standby. If the application has separate read and write URLs, check the exact connection string used by the failing job or request. In a SQL session, pg_is_in_recovery() returns true on a standby.

Then look for two clues: long-running standby queries and replica lag. On the standby, pg_stat_activity shows queries with old start times. PostgreSQL also exposes WAL receive and replay positions through functions such as pg_last_wal_receive_lsn() and pg_last_wal_replay_lsn(). On the primary, pg_stat_replication helps show whether the standby is behind at the write, flush, or replay stage.

SymptomLikely causeSafer first response
Large report fails on a read replicaQuery snapshot conflicts with WAL replay or cleanupShorten the report, paginate it, or run it on a dedicated analytics path
Error appears after a migrationStandby replay needs locks for DDL from the primaryAvoid routing schema-sensitive reads to replicas during migrations
Replica lag grows when conflicts stop happeningDelay settings or feedback may be protecting queries too muchRevisit freshness requirements before increasing standby delays further
API read fails soon after a writeRead-after-write traffic is routed to a stale or recovering replicaRoute that request path to the primary or use explicit consistency rules
Conflicts mention vacuum cleanupStandby snapshot needs row versions the primary vacuum wants removedShorten standby transactions; consider feedback only with bloat monitoring

Fix the query path first

For most application incidents, the best first fix is not a server setting. It is routing and query shape. If a request must see data immediately after a write, send it to the primary. Read replicas are excellent for tolerant reads, background exports, and dashboards, but they are a poor default for user flows that require fresh results after a mutation.

If the query is a report, make it less hostile to recovery. Add selective predicates, paginate by a stable key, avoid open-ended exports during peak write periods, and make sure the query uses appropriate indexes. A five-minute sequential scan on a hot table is much more likely to conflict than a focused query that returns the same business answer in seconds.

For migrations, reduce surprise by treating replicas as temporarily inconsistent readers. DDL on the primary can create recovery conflicts on standbys. During a migration window, route admin screens, jobs, and schema-introspecting tools carefully. If a deploy runs a migration and a long standby query simultaneously, the cancellation may be the replica protecting recovery rather than a random failure.

When settings are involved

PostgreSQL has standby delay settings, including max_standby_streaming_delay, that control how long a standby may wait before canceling conflicting queries while applying streamed WAL. Increasing the delay can help long reads finish, but it directly trades off replica freshness. A replica that waits longer may serve older data for longer.

Another setting, hot_standby_feedback, lets a standby tell the primary about queries that need old row versions. That can reduce some cleanup conflicts, but it can also prevent vacuum from removing dead tuples on the primary, increasing table and index bloat if long standby transactions are common. It is a real operational tradeoff, not a harmless switch.

In managed PostgreSQL, you may not control every parameter directly, and that is often a good thing. Before asking a provider to change replica-conflict settings, write down the workload goal: fresher replicas, fewer canceled reports, or safer read-after-write behavior. Those goals are different. ArmorDB users should pair replica reads with normal connection-pool discipline and keep consistency-sensitive code paths on the primary unless the application explicitly tolerates lag.

Validate the fix

After changing routing, query shape, or settings, test the same workload from the same runtime that failed. Confirm that the query completes, that replica lag remains within the application's tolerance, and that the primary is not accumulating avoidable bloat because standby reads stay open too long. A successful fix is not only "the error disappeared." It is that the replica can keep replaying WAL while the application gets the consistency level it expects.

Add a short runbook entry that names which services may use replicas, which must use the primary, and what lag or cancellation alerts mean. Without that distinction, teams often rediscover the same conflict during every large report, migration, or customer import.

Takeaway

canceling statement due to conflict with recovery means a standby read got in the way of replaying primary changes. Fix it by matching reads to their consistency needs, shortening expensive replica queries, and tuning standby conflict settings only after deciding how much lag is acceptable. The safest production posture is to reserve replicas for reads that can tolerate delay and keep critical read-after-write paths on the primary.

Sources and further reading

Topic

Short-Form & Quick Fixes

Updated

Jul 7, 2026

Read time

5 min read

About the author

ArmorDB Engineering writes about PostgreSQL operations, security, and infrastructure decisions for teams building production apps on ArmorDB.