SQLSTATE 40P01Severity highLab verified

Incident brief

Deadlock detected

Two or more transactions waited on locks held by each other, forming a cycle. PostgreSQL detected the deadlock and aborted one transaction so the others could continue.

Reproduced on PostgreSQL 16.14Verified 2026-07-14 (Docker lab, PostgreSQL 16.14)Reviewed by Verified against PostgreSQL 16.14 in an isolated lab environment

In 10 seconds

What
Deadlock detected
What triggers it
Session A updates row 1 and keeps the transaction open.
The fix
Roll back and retry the aborted transaction.
Proof
Reproduced on PostgreSQL 16.14 → In this lab run, session B's transaction was cancelled by PostgreSQL's deadlock detector and rolled back; session A's transaction committed. Which participant gets aborted is decided internally by PostgreSQL's deadlock detector and should not be relied upon — a different run of the same cycle could cancel the other session instead.

The fix

What to do right now

The immediate, application-level response to this error.

Recovery Act now

  • Roll back and retry the aborted transaction.

Prevention Safe

  • Enforce a single, consistent lock acquisition order across the codebase.
  • Split overly broad transactions into smaller atomic units so lock windows shrink.
Fix — SQL
-- standardize row access order
BEGIN;
UPDATE inventory SET quantity = quantity - 1 WHERE id = 1;
UPDATE inventory SET quantity = quantity - 1 WHERE id = 2;
COMMIT;

-- all concurrent workers must follow the same order: 1 then 2

Verification

PG 16.14
Last verified
2026-07-14 (Docker lab, PostgreSQL 16.14)
Reviewed by
Verified against PostgreSQL 16.14 in an isolated lab environment
Audit status
reviewed