Home / Tutorials / PostgreSQL

PostgreSQL · Database · Degraded

Fix: canceling statement due to statement timeout

Error canceling statement due to statement timeout

By the Erzon engineering team · A step-by-step fix, not a forum thread

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.

  1. DIAGNOSE: find the current timeout and where it comes from.
SHOW statement_timeout;
SELECT name, setting, source FROM pg_settings WHERE name = 'statement_timeout';
  1. 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
  1. DIAGNOSE: run the offending query with EXPLAIN ANALYZE in 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 ...;
  1. 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';
  1. 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);
  1. 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_timeout per 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_statements for queries whose mean time is trending toward the timeout.
  • Run ANALYZE after 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

Still down after this?

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

← Back to all error fixes

Still down?

Get a senior engineer on it now

Leave your email and a line about what is happening. A senior engineer replies within one business hour with what is likely wrong and a flat quote. Triage is free.

Or email [email protected]. Same engineers, same one-hour clock.