DatabaseHigh
Fix: PostgreSQL Deadlock Detected
Application errors: 'ERROR: deadlock detected'
!Symptoms
- Application errors: 'ERROR: deadlock detected'
- Transactions fail intermittently under load
- PostgreSQL log shows 'Process X waits for Y on relation Z; blocked by process W'
- Slow queries and connection pool exhaustion during peak traffic
?Root Causes
- Two or more transactions acquiring locks on the same rows in different order
- Long-running transactions holding locks while waiting for other locks
- Bulk UPDATE/DELETE operations conflicting with concurrent transactions
- Missing indexes causing table-level locks instead of row-level locks
- Application logic that opens a transaction and waits for external I/O
#Diagnosis Steps
- 1Check PostgreSQL logs for the full deadlock detail including the queries involved
- 2Find current locks: `SELECT * FROM pg_locks WHERE NOT granted;`
- 3Find blocking queries: `SELECT * FROM pg_stat_activity WHERE pid IN (SELECT pid FROM pg_locks WHERE NOT granted);`
- 4Check for long-running transactions: `SELECT pid, now() - xact_start, query FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY 2 DESC;`
- 5Enable log_lock_waits in postgresql.conf for future debugging
>Fix
- 1Ensure all transactions access tables and rows in a consistent order
- 2Break large UPDATE/DELETE into smaller batches
- 3Add appropriate indexes to reduce lock scope (row-level vs. table-level)
- 4Set lock_timeout to fail fast instead of waiting indefinitely: `SET lock_timeout = '5s';`
- 5Add retry logic in the application for deadlock errors (SQLSTATE 40P01)
*Prevention
- Design transactions to acquire locks in a consistent global order
- Keep transactions as short as possible: no external I/O inside transactions
- Use SELECT ... FOR UPDATE SKIP LOCKED for queue-like patterns
- Monitor deadlock frequency with pg_stat_database.deadlocks
- Enable log_lock_waits and deadlock_timeout for visibility
Related Error Messages
ERROR: deadlock detectedDETAIL: Process X waits forSQLSTATE 40P01canceling statement due to lock timeoutcould not obtain lock on row