Symptom triage
Production transaction bugs announce themselves as one of five symptoms. Each row maps a symptom to the lesson that proves the mechanism and the lesson that fixes it — this page is the index you paste into the incident channel.
| Symptom | First check | Mechanism | Fix |
|---|---|---|---|
| Updates hang, then finish | Who is blocking whom | lock queues | end the blocker; shorter transactions |
Updates hang, then errno 1205 | Who is blocking whom | lock wait timeout — statement rollback only! | retry after ROLLBACK; find the blocker |
Errno 1213 in the logs | the deadlock counter | deadlocks, gap locks | consistent lock order; retry loop |
| INSERTs stuck with no row conflict | data_locks for GAP / INSERT_INTENTION | gap locks | READ COMMITTED for the writer, or narrower locking reads |
| Numbers wrong, no errors anywhere | the anomaly catalog | lost updates, write skew | the three fixes |
| Disk grows, queries don't slow | history list health | an old read view pins purge | end the long transaction |
| DDL hangs and takes the app with it | processlist: Waiting for table metadata lock | metadata locks | lock_wait_timeout on the DDL session |
Two MySQL-specific reflexes are worth building on top of that table. Start with this one: errors that look alike often aren't. 1205 rolls back a single statement and leaves the transaction open, still holding its locks, while 1213 rolls back the whole transaction. Handling the two identically is pitfall material.
The second reflex: silence isn't health. The costliest failures on this table — lost updates, write skew, purge lag — throw no error at all, so you catch them with counters and invariant checks, never by grepping logs.