Concurrency control
Trace a deadlock to the order of resource access
Retrying can recover one request, but repeated deadlocks need a clearer picture of which transactions acquire which resources.
In this article
Capture the competing operations
Start with the database's deadlock report and the affected application operation identities. Identify the resources and statements involved without exposing sensitive parameter values.
A deadlock differs from a long lock wait. In a deadlock, transactions form a cycle of dependencies. Merely increasing a timeout does not remove that cycle.
Check the user-visible outcome. The application should handle the database's aborted transaction according to its retry policy, rather than returning success for work that did not commit.
Reconstruct the access order
An illustrative transfer operation locks account A and then account B. Another path locks B and then A. Under overlap, each can hold the resource the other needs.
Compare all paths touching those records, including scheduled reconciliation and support actions. A consistent order in one endpoint does not help if another path uses the opposite order.
Look beyond explicit lock statements. Updates, foreign-key checks and other database operations can participate in locking. Use the actual database evidence rather than assuming only code containing a lock keyword matters.
Reduce the avoidable overlap
Where appropriate, acquire shared resources in a consistent order. Keep transactions focused and avoid waiting for user input or slow external services while holding database locks.
Review whether the operation locks more rows than its invariant requires. A broad query can create contention unrelated to the business action.
Do not weaken correctness controls simply to eliminate an alert. Removing a lock may replace visible deadlocks with silent data corruption. Reproduce the intended invariant in tests before changing the boundary.
Verify retry and recovery
Retry the entire aborted transaction when the database and operation policy require it. Re-read the state needed for the decision and apply a bounded retry budget.
External effects need separate protection because an aborted database transaction cannot undo a previously sent request to another service. Confirm that retries do not duplicate those effects.
After the fix, run the conflicting paths together and inspect both deadlock frequency and business results. Keep the observed resource cycle in the incident record so future changes can be reviewed against the specific cause.
Primary sources
PostgreSQL: explicit lockingReferences checked 11 September 2026.