PostgreSQL: deadlock detected
ERROR: deadlock detectedTwo transactions each hold a lock the other needs, so neither can proceed. Postgres breaks the tie by aborting one of them. The durable fix is to acquire locks in a consistent order, keep transactions short, and retry on this error.
What this error means
A deadlock happens when transaction A holds a lock on one row and wants a second, while transaction B holds the second and wants the first. Neither can move, so Postgres detects the cycle and cancels one transaction with this error. The DETAIL and server log show the two statements involved.
It is a concurrency problem, not a data problem, and it is expected under contention. Well-behaved apps retry the aborted transaction.
How to fix it
Transactions lock rows in different orders
Always acquire locks in the same order across every code path, for example by updating the lower id first.
The transaction is retryable
Catch SQLSTATE 40P01 and retry the whole transaction, ideally with a short backoff.
You need to see what collided
The server log records both queries. The DETAIL line names the two backend PIDs and the locks they waited on.
-- check the server log around the deadlock for the two statementsHow to avoid it next time
- Use a consistent lock ordering everywhere, and keep transactions short.
- Keep the retry: you cannot guarantee zero deadlocks under real concurrency.
Frequently asked questions
Is a deadlock a bug in Postgres?
No. It is a normal outcome of concurrent transactions competing for locks in different orders. Postgres resolves it by aborting one; your app should retry.
How do I stop deadlocks entirely?
Acquire locks in a consistent order everywhere and keep transactions short. You cannot fully guarantee zero, so keep retry logic.
Stop struggling with SQL
Use FluentDB, the AI database client for macOS.
Related errors
Part of the PostgreSQL error reference. Last reviewed 2026-07-31.