PostgreSQL error: deadlock detected

ERROR:  deadlock detected
DETAIL:  Process 18461 waits for ShareLock on transaction 1064; blocked by process 18463.
Process 18463 waits for ShareLock on transaction 1063; blocked by process 18461.
HINT:  See server log for query details.
CONTEXT:  while updating tuple (0,3) in relation "accounts"

Two (or more) transactions are each waiting for a lock the other one holds. Neither can ever proceed, so PostgreSQL detects the cycle, picks one transaction as the victim and aborts it with this error. The other transaction continues normally.

What this error means

Row-level locks in PostgreSQL are held until the transaction commits or rolls back. If transaction A locks row 1 and then wants row 2, while transaction B holds row 2 and wants row 1, they form a cycle: a deadlock. When a backend has been waiting on a lock for longer than deadlock_timeout (default: 1 second), PostgreSQL runs a deadlock check; if it finds a cycle, it aborts one of the participants with SQLSTATE 40001's sibling 40P01.

Important framing: the database has already resolved the situation by the time you see the error. Nothing is corrupted and the surviving transaction completed its lock wait. What's left is an application problem — the aborted transaction was rolled back and its work is gone, so your application must be prepared to retry it.

Common causes

How to diagnose it

The error itself carries most of what you need:

Set log_lock_waits = on to also log any lock wait longer than deadlock_timeout, which shows you the near-misses, not just the collisions. For live investigation of who blocks whom:

SELECT waiting.pid  AS waiting_pid,  waiting.query  AS waiting_query,
       blocking.pid AS blocking_pid, blocking.query AS blocking_query
FROM pg_stat_activity waiting
JOIN pg_stat_activity blocking
  ON blocking.pid = ANY (pg_blocking_pids(waiting.pid));

How to fix it

🔍 Related reading: Transaction isolation levels — the "Retrying correctly" section applies to deadlocks too: retry the whole transaction, not the failed statement.