The Runtime Theory
mediumApplicationDSA#concurrency#transactions#locking

What is a deadlock and how does the database resolve it?

The interviewer is testing whether you understand lock-based concurrency failure — the wait-for graph, detection versus timeouts, victim selection, and what the application must do.

The Runtime Theory Team2 min readasked at stripe · palantir · microsoft

A deadlock is the failure mode of lock-based concurrency: transaction A holds row X and wants row Y; transaction B holds row Y and wants row X. Each is waiting for the other; neither can proceed; without intervention, both wait forever. The database doesn't let that happen — it detects the cycle and kills one side.

The mechanics start with two-phase locking, which is what makes the window for deadlocks at all. A transaction acquires locks as it executes and holds them until commit; locks are never released early. So over the life of a transaction, the set of rows it holds grows, and two transactions operating on overlapping rows in different orders can always interleave into a cycle.

Detection is a graph problem. The database tracks a wait-for graph: nodes are transactions, and an edge from T1 to T2 means "T1 holds something T2 wants." A deadlock is a cycle in that graph. Postgres checks the graph periodically (every deadlock_timeout, default 1 second — the same parameter that doubles as lock-wait reporting) and, on finding a cycle, aborts the transaction that's cheapest to sacrifice — the one that has done the least work — and returns error 40P01: deadlock detected. MySQL with innodb_deadlock_detect = ON (default) does the same continuously. The victim's transaction is rolled back completely, and its locks are released, which unblocks the survivor. If the database didn't detect, a lock_timeout would eventually abort one waiter anyway — but that's a timeout, not a cycle-aware choice, and it can kill the wrong transaction.

The interviewer wants to know you've been hit by this. Deadlocks are nearly always an application design smell, not a database bug, and there are standard fixes. Lock ordering: if every transaction touches rows in the same order (smallest ID first, say), cycles can't form. Short transactions: the less time locks are held, the smaller the window — a transaction that does its reads, pauses for user input, then writes is a deadlock factory. Consistent index access order for joins — the optimizer's join order determines acquisition order, and different plans can lock the same rows in different orders. Unique index conflicts are the classic surprise: two transactions inserting the same key create an insert-intent wait that can cycle with other locks.

Close with the retry story: since the victim's transaction is aborted wholesale, the application must retry the entire transaction, not the failed statement — and a small randomized backoff makes the retry far less likely to cycle again. The database resolves the deadlock; the application resolves the recurrence.

This answer walks

Follow-ups they'll push on

  1. 01Your app gets deadlock errors in production. What do you look at first?
  2. 02Why is deadlock detection periodic rather than instant?
  3. 03What's the difference between a deadlock and a lock timeout?

More interviews in this topic

One dispatch a week

The trace behind each question, the tradeoff that explains it, and one technical dispatch per week — no noise.

One technical dispatch per week. No noise.