Skip to main content
Metrics type: Key MetricsCategory: Performance

At a glance

The number of InnoDB deadlocks detected in the last 5 minutes. A deadlock is two (or more) transactions each holding a lock the other needs, so InnoDB breaks the cycle by killing one of them with error 1213, Deadlock found when trying to get lock. For a DBA, this is “are concurrent transactions colliding on the same rows in incompatible lock orders?” A clean instance shows zero. Anything above zero means at least one transaction was rolled back, and if your application does not retry it, a user saw an error. This is why the alert fires at the first deadlock, not at a threshold.

Calculation

The engine reads Innodb_deadlocks from SHOW ENGINE INNODB STATUS, snapshots it, and reports the delta over the trailing 5 minutes:
A restart guard applies: if the instance restarted inside the window (the counter reset to zero and Instance Uptime dropped), the engine treats the current value as the delta so the reading never goes negative. Crucially, SHOW ENGINE INNODB STATUS only retains the single most recent deadlock in its LATEST DETECTED DEADLOCK section, so the headline count and the drill-down detail can diverge: the count can read 4 while the detail shows only the last collision. To capture every deadlock for forensics you need innodb_print_all_deadlocks = ON, which writes each one to the MySQL error log; the card surfaces a hint to enable it when the count exceeds 1 but the detail shows only one event. The drill-down parses the latest deadlock’s two transaction blocks (the statements, the locks held, and the locks waited on) and the line naming which transaction InnoDB chose as the rollback victim (usually the one with the fewer rows modified, as it is cheaper to undo).

Worked example

A platform team runs a MySQL 8.0 primary behind an inventory service. On 18 Apr 26 at 20:05 BST, during an evening flash-sale, the card jumps to 6 deadlocks in 5m, tripping the > 0 alert for the first time in weeks. The drill-down shows the LATEST DETECTED DEADLOCK: InnoDB rolled back T2 (fewer rows modified) and let T1 commit. The pattern is textbook: two checkout transactions decrementing stock for the same two SKUs but acquiring the row locks in opposite order. Under low traffic the windows never overlap; under flash-sale concurrency they collide constantly.
The immediate mitigation is application-side: ensure the retry logic actually catches error 1213 and replays the transaction (a deadlock victim is safe to retry because it was fully rolled back). The durable fix is to make every transaction lock rows in a consistent order, for example always sort the SKU ids ascending before the updates, so two transactions touching 8841 and 9102 both lock 8841 first and one simply waits instead of deadlocking. Once the deploy ships, the card returns to zero even at peak concurrency. Three takeaways:
  1. One deadlock means one rolled-back transaction. If your application retries on 1213, the user never notices; if it does not, the user saw an error. The alert fires at the first deadlock because you cannot tell from the count alone whether a user was affected.
  2. Deadlocks are a concurrency and lock-ordering problem, not a hardware problem. Throwing CPU or memory at them does nothing. The fix is almost always consistent lock ordering, shorter transactions, or appropriate retry logic.
  3. The count and the detail can disagree. Native InnoDB status keeps only the latest deadlock. If the count is 6 but you can only see one collision, enable innodb_print_all_deadlocks so every event lands in the error log for analysis.

Sibling cards to reference together

Reconciling against the source

Where to look in MySQL’s own tooling:
Run SHOW ENGINE INNODB STATUS\G and read the LATEST DETECTED DEADLOCK section for the most recent collision, plus the Innodb_deadlocks line for the lifetime counter. Check SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks'; for the raw since-restart total (the card reports only the 5-minute delta of this). Enable SET GLOBAL innodb_print_all_deadlocks = ON; to write every deadlock to the error log (SELECT @@log_error; for the path), since the status output keeps only the latest one. Inspect live lock waits with SELECT * FROM performance_schema.data_lock_waits; and the sys.innodb_lock_waits view to see contention before it becomes a deadlock.
Why our number may legitimately differ from a raw status read: Managed-service cross-checks:

Known limitations / FAQs

The card says 4 deadlocks but SHOW ENGINE INNODB STATUS only shows one. Why? Native InnoDB status retains only the single most recent deadlock in its LATEST DETECTED DEADLOCK section. The counter increments for every deadlock, but the detail is overwritten each time. To see all four, enable innodb_print_all_deadlocks = ON so each one is written to the error log. The card’s count is correct; the native detail view is simply lossy by design. Is a deadlock the same as a lock-wait timeout? No, and conflating them leads to the wrong fix. A deadlock (error 1213) is a true cycle that InnoDB detects and resolves instantly by rolling back a victim. A lock-wait timeout (error 1205) is a transaction that waited longer than innodb_lock_wait_timeout for a lock that was never going to deadlock, just held too long. Deadlocks point at lock-ordering; timeouts point at long-held locks or an oversized innodb_lock_wait_timeout. This card counts only the former. Should I always treat a deadlock as an incident? Not necessarily, but always investigate. In a healthy concurrent system the occasional deadlock is expected and the correct response is application-side retry, not a code change. The alert fires at the first deadlock because the count alone cannot tell you whether the application retried the victim or surfaced an error to a user. If your retry logic is solid and the rate is low, log it and move on; if the rate is climbing or there is no retry logic, fix it. How do I actually stop deadlocks? Three durable techniques, in order of impact: (1) lock rows in a consistent order across all transactions (for example always sort ids ascending before updating), which converts most deadlocks into harmless brief waits; (2) keep transactions short so lock windows do not overlap; (3) add appropriate indexes so InnoDB locks fewer rows. Retry logic is a safety net, not a fix, it handles the deadlocks you could not design away. Which transaction does InnoDB roll back? InnoDB picks the victim it judges cheapest to undo, normally the transaction that has modified the fewest rows. This is why a small transaction can be rolled back in favour of a large one. You cannot reliably predict the victim, which is exactly why every transaction that might deadlock needs retry handling rather than assuming it will be the survivor. Why did the count spike during a sale but never during normal traffic? Deadlocks are a function of concurrency on the same rows. At low traffic, two transactions touching the same hot rows in opposite lock order rarely overlap in time. At high concurrency on a few hot SKUs, those windows overlap constantly and the latent lock-ordering bug becomes visible. The bug was always there; traffic exposed it. Fix the lock ordering and it stays at zero even at peak. Does the counter include deadlocks on replicas? The card reports the deadlock counter for the instance it is reading. A replica applying writes single-threaded rarely deadlocks against itself, but with parallel replication appliers it can. If you see deadlocks on a replica, check the parallel-applier settings; on the primary, deadlocks come from concurrent application transactions as described above.

Tracked live in Vortex IQ Nerve Centre

InnoDB Deadlocks (last 5m) is one of hundreds of KPI pulses Vortex IQ tracks across MySQL and 70+ other ecommerce connectors. Nerve Centre runs the detection layer; Vortex Mind investigates the cause when something moves; Ask Viq lets you interrogate any number in plain English. Start for free or book a demo to see this metric running on your own data.