MySQL Deadlock Elimination: 9 Golden Rules and Production‑Ready Defense
Deadlocks in MySQL are not random glitches but the inevitable result of uncontrolled concurrency, lock granularity, transaction boundaries, and resource ordering; this article explains the underlying lock mechanisms, common deadlock scenarios, and presents nine practical, production‑grade rules for architecture design, lock management, and observability to keep deadlocks within acceptable SLA limits.
Why deadlocks spike during peak periods
Teams often first encounter deadlocks during large promotions, month‑end settlements, batch windows, or minutes after a hot activity starts. The symptom is not a single error code but a cascade: API latency spikes, active DB connections surge, thread‑pool queues grow, upstream services mistakenly scale traffic, and eventually a full‑stack avalanche.
Fundamental insight: deadlock is a concurrency mismatch
Deadlock is not a single‑SQL issue; it involves four layers:
Transaction layer : overly long transactions that embed RPC, MQ, file I/O, or heavy computation.
Lock layer : hitting unique indexes, gap locks, next‑key locks, or insert‑intention locks.
Application layer : different code paths acquiring the same resources in different orders.
Architecture layer : hot data concentration, distributed long‑running transactions, and batch‑online table contention.
Effective deadlock mitigation must answer three questions:
Why does the deadlock occur?
Which code paths are most prone?
How to ensure a deadlock does not become a service‑level incident?
Clarifying concepts
Lock wait
Transaction A holds a row lock; transaction B waits for that row. If the wait‑graph has no cycle, this is ordinary blocking, not a deadlock.
Lock wait timeout
If B waits longer than innodb_lock_wait_timeout, MySQL reports a timeout. Timeout indicates “waited too long” but not necessarily a cycle.
Deadlock
When A waits for B and B waits for A, a cycle forms. InnoDB detects the cycle and rolls back a victim transaction.
In production, the handling differs:
Lock wait: shorten transactions, add indexes, reduce hotspots.
Lock timeout: apply rate‑limiting, batch splitting, shorten transaction duration.
Deadlock: enforce a unified lock order, shrink lock scope, design retry‑friendly semantics.
InnoDB lock fundamentals
InnoDB maintains a lock‑wait graph. A cycle like T1 → T2 → T3 → T1 triggers a deadlock. The engine chooses the victim based on rollback cost (rows modified, locks held, etc.).
Four textbook lock properties map to MySQL as follows:
Mutual exclusion : row lock, gap lock, next‑key lock, metadata lock.
Request‑and‑hold : a transaction may request a new lock while holding others.
Non‑preemptive : locks are released only on commit/rollback.
Circular wait : different code paths acquire locks in opposite orders, forming a wait‑ring.
Common deadlock patterns
1. Inconsistent lock order
Typical payment scenario:
Transaction A: lock account → lock orders
Transaction B: lock orders → lock accountEven with different order IDs, if both touch the same user balance row, a classic two‑resource deadlock occurs.
2. Index path mismatch
Similar SQL statements may use different indexes, expanding lock ranges. Example:
UPDATE orders SET status='PAID' WHERE order_id=10001;
UPDATE orders SET status='PAID' WHERE user_id=20001 AND status='INIT';The first uses a primary‑key lookup (tiny lock), the second may trigger a range lock on a non‑unique index, dramatically increasing lock contention.
3. Hidden hotspots
Locks on metadata (DDL vs DML) can also cause deadlocks, especially when an online DDL runs alongside regular updates.
9 Golden Rules for production‑grade deadlock mitigation
Rule 1 – Minimize transaction scope
Only keep state‑changing operations inside the transaction. External calls (RPC, MQ, heavy calculations, file I/O) should be performed outside the lock window.
@Transactional
public void pay(...) {
// bad: remote calls inside transaction
}Correct approach:
public void pay(...) {
// pre‑checks outside transaction
deadlockRetryExecutor.execute(() -> transactionTemplate.executeWithoutResult(this::doPay));
}Rule 2 – Review lock‑SQL with index semantics
Every UPDATE, DELETE, or SELECT … FOR UPDATE must be proven to hit a high‑selectivity index. The four mandatory checks are: UPDATE … WHERE – condition must use a selective index. DELETE … WHERE – condition must hit an index. SELECT … FOR UPDATE – lock range must be predictable.
Batch scans – must use stable ordered pagination keys.
Rule 3 – Enforce a global lock order
Define a unified acquisition sequence (e.g., account → orders → coupon) and generate a lock plan in code to guarantee the order.
enum LockLevel { ACCOUNT(10), ORDER(20), COUPON(30); }
// sort resources by level before issuing SELECT … FOR UPDATERule 4 – Use FOR UPDATE cautiously
Only lock rows with a unique key or a clearly bounded range. Non‑unique or range locks can lock large index gaps and cause massive contention.
Rule 5 – Choose the right isolation level
MySQL defaults to REPEATABLE READ, which introduces gap/next‑key locks. For high‑throughput OLTP, READ COMMITTED often reduces lock footprint without harming correctness.
Rule 6 – Treat deadlocks as recoverable exceptions
Implement retry logic with exponential back‑off, limited attempts, and idempotent operations (e.g., requestId + INSERT IGNORE).
public T execute(Supplier<T> action) {
for (int i = 1; i <= MAX_RETRY; i++) {
try { return action.get(); }
catch (Exception e) { if (!isDeadlock(e) || i == MAX_RETRY) throw e; sleepWithJitter(i); }
}
throw last;
}Rule 7 – Split hotspots
Logical bucket tables, pre‑deduction with asynchronous aggregation, or sharding by user/store ID turn a single‑row hotspot into many low‑contention rows.
Rule 8 – Isolate online traffic from batch jobs
Batch tasks must paginate, limit batch size, use stable primary‑key order, and avoid running during traffic peaks.
Rule 9 – Build a closed‑loop observability system
Collect three categories of metrics:
Database side: SHOW ENGINE INNODB STATUS, performance_schema.data_locks, deadlock count, lock wait time, rows scanned.
Application side: deadlock error count, lock‑timeout count, retry statistics, transaction latency percentiles.
Business side: payment success rate, order‑state failure rate, compensation volume.
Log sufficient context (request ID, business key, entry method, involved resources, retry count, SQLState/ErrorCode) and set up alerts (e.g., Prometheus rule for a spike in innodb_deadlocks).
Root‑cause analysis workflow (≤15 min)
Identify error code: 1213 = deadlock, 1205 = lock‑wait timeout.
Fetch current wait graph via SHOW ENGINE INNODB STATUS or information_schema.INNODB_LOCK_WAITS to answer “who waits for whom” and “which resource”.
Correlate with application logs (request ID, order ID) to map the two transactions to code paths.
Classify the root cause (long transaction, missing index, order mismatch, isolation‑level gap lock, hotspot, batch‑online mix).
Apply immediate “stop‑bleed” actions: rate‑limit hot APIs, pause large batch jobs, shrink batch size, add temporary limits.
Plan permanent fixes: refactor transaction boundaries, add/adjust indexes, enforce lock order, switch isolation level, shard hotspots, introduce Outbox for async side‑effects.
Common misconceptions
Deadlocks are not merely a performance issue.
Adding an index reduces lock range but does not guarantee deadlock‑free execution.
Even rare deadlocks must be engineered as recoverable.
Large transactions increase both lock window and rollback cost.
Deadlocks can involve range locks, insert‑intention locks, and metadata locks—not just the same row.
Final takeaway
Deadlock probability ≈ lock‑hold‑time × lock‑range × order‑inconsistency × hotspot‑concurrency. Effective mitigation spans design (state machines, async processing, sharding), development (unified lock order, index‑first lock SQL, retry handling), database configuration (appropriate isolation level, short transactions), and operations (metrics, alerts, rehearsed incident response). By treating deadlocks as a regular, recoverable exception, systems can maintain stability even under extreme load.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Cloud Architecture
Focuses on cloud‑native and distributed architecture engineering, sharing practical solutions and lessons learned. Covers microservice governance, Kubernetes, observability, and stability engineering to help your systems run stable, fast, and cost‑effectively.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
