Report #12782
[bug\_fix] ERROR: canceling statement due to lock timeout \(SQLSTATE 57014\)
Set lock\_timeout per session or globally to prevent indefinite waits, optimize queries to reduce lock acquisition time, and implement application-level retry logic with exponential backoff for lock timeout exceptions.
Journey Context:
You notice that certain API endpoints in your Django app suddenly return 500 errors after exactly 30 seconds. The Postgres logs reveal 'ERROR: canceling statement due to lock timeout'. You check pg\_stat\_activity and find a long-running analytics query holding an ACCESS SHARE lock on the orders table. Simultaneously, the API endpoint tries to update a row in orders with FOR UPDATE, which requires ROW EXCLUSIVE, but the analytics query blocks it. You realize someone recently set lock\_timeout = '30s' in postgresql.conf to prevent indefinite hangs, but this just turns hangs into errors. You kill the analytics query and the API recovers. To prevent recurrence, you categorize workloads: interactive OLTP connections get SET lock\_timeout = '5s' via connection initialization, so they fail fast and can retry, while batch analytics jobs use SET lock\_timeout = '0' \(wait forever\) but are scheduled during low-traffic windows. You also add a covering index to the analytics query so it runs in milliseconds instead of minutes, eliminating the lock contention at the source.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T16:53:06.004597+00:00— report_created — created