PostgreSQL raised this error because a query ran longer than the statement_timeout setting allows, so the server canceled it. This is a protective limit, not a malfunction: it stops one slow query from pinning a connection, holding locks, and dragging everything else down. When you see it in production, either a query got slower than it used to be, or a legitimately long job is running under a timeout meant for short web requests.
ERROR: canceling statement due to statement timeout
What this error means
statement_timeout is a per session limit on how long any single statement may run. It can be set globally in postgresql.conf, per database, per role, per session, or by the client driver. When a statement exceeds the limit, PostgreSQL cancels it, returns this error, and aborts the current transaction. The setting itself is behaving exactly as configured. The error is a symptom of a mismatch between how long the query takes and how long something decided it is allowed to take.
Common causes
- A query plan regressed: a table grew, statistics went stale after a bulk load, or an index was dropped, and a query that used an index scan now sequentially scans millions of rows.
- Lock waits: the query is not slow, it is blocked behind another transaction holding a lock, and the timeout expires while it waits.
- A batch job, report, or migration running through a connection pool configured with a short timeout intended for web traffic.
- The timeout was set very low by a framework or pooler default (some ORMs and PgBouncer setups inject their own value) without anyone realizing.
- Missing indexes on a new query pattern, so a feature that worked in staging times out at production data volume.
- Table or index bloat after heavy update or delete traffic, making every scan touch far more pages than the live rows justify.
How to fix it
STABILIZE first. If a critical job is failing right now, raise the timeout for that session only and rerun it, then investigate the slowness properly.
- DIAGNOSE: find the current timeout and where it comes from.
SHOW statement_timeout;
SELECT name, setting, source FROM pg_settings WHERE name = 'statement_timeout';
- DIAGNOSE: identify which queries are hitting the limit. The cancellation is logged on the server with the full query text.
grep "statement timeout" /var/log/postgresql/postgresql-*.log | tail -20
- DIAGNOSE: run the offending query with
EXPLAIN ANALYZEin a session where you have lifted the limit, and look for sequential scans on large tables, misestimated row counts, and time spent waiting.
SET statement_timeout = 0;
EXPLAIN (ANALYZE, BUFFERS) SELECT ...;
- DIAGNOSE: check whether the query is actually blocked rather than slow.
SELECT pid, wait_event_type, wait_event, state, query
FROM pg_stat_activity
WHERE state != 'idle';
- FIX according to what you found. If the plan is bad because statistics are stale, refresh them:
ANALYZE orders;
If an index is missing for the access pattern, add it without blocking writes:
CREATE INDEX CONCURRENTLY idx_orders_customer_created
ON orders (customer_id, created_at);
- FIX the configuration mismatch. Give long running work its own role with an appropriate limit instead of loosening the global setting:
CREATE ROLE reporting LOGIN;
ALTER ROLE reporting SET statement_timeout = '15min';
Keep the application role tight, for example 5s for web request traffic, so runaway queries still fail fast.
How to prevent it
- Set
statement_timeoutper role: short for web traffic, longer for reporting, migrations, and batch jobs. - Enable
log_min_duration_statement(for example 1000 ms) so queries show up in the log as they get slow, before they start timing out. - Watch
pg_stat_statementsfor queries whose mean time is trending toward the timeout. - Run
ANALYZEafter bulk loads and large deletes so the planner works from current statistics. - Review query plans when tables cross size milestones; a plan that is fine at one million rows can collapse at fifty million.
- Make the application retry canceled statements idempotently instead of surfacing the raw error to users.
When to call a senior engineer
Call for help when queries keep timing out after you have added the obvious indexes, when plans flip between good and bad seemingly at random, or when the timeouts cluster during specific windows and you suspect lock contention or autovacuum interference you cannot pin down. Erzon engineers can read the plans, find the real bottleneck in your workload, and leave you with per role timeouts and indexes that keep the error from coming back.
Related errors we fix
ERROR: could not extend file "base/16384/24576": No space left on device Fix this error → PostgreSQL could not resize shared memory segment ... : No space left on device Fix this error → PostgreSQL ERROR: deadlock detected Fix this error → PostgreSQL FATAL: sorry, too many clients already Fix this error → Want a senior engineer to just fix it?
Paste this exact error into the form. A senior engineer replies within one business hour with what is likely wrong and a flat quote. Triage is free.
Book a fix