ERROR 1213 (40001): Deadlock found when trying to get lock
Error Message
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Description
A deadlock occurs when two or more transactions are waiting for each other to release locks, creating a cycle where none of the transactions can proceed. MySQL's InnoDB engine automatically detects deadlocks and resolves them by rolling back one of the transactions (the "victim").
Causes
- Transactions accessing the same rows in different orders
- Transactions that hold locks for extended periods
- Many transactions competing for the same resources
- Row-level locks escalating to page or table locks
- Missing or improper indexes causing table scans
- Applications accessing data in unpredictable sequences
- Foreign key constraints causing lock contention
- Gap locks in REPEATABLE READ isolation level
Solutions
-
Implement retry logic in your application:
# Python example max_retries = 3 retry_count = 0 while retry_count < max_retries: try: # Start transaction cursor.execute("START TRANSACTION") # Perform database operations cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1") cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2") # Commit transaction cursor.execute("COMMIT") break # Success, exit the loop except mysql.connector.Error as err: if err.errno == 1213: # Deadlock error code # Rollback and retry cursor.execute("ROLLBACK") retry_count += 1 time.sleep(0.5 * retry_count) # Exponential backoff else: # Other error, raise it raise
-
Standardize transaction access patterns:
-- Always access tables in alphabetical order -- Instead of: UPDATE accounts SET ... WHERE ... UPDATE users SET ... WHERE ... -- Use consistent ordering: UPDATE accounts SET ... WHERE ... UPDATE zones SET ... WHERE ...
-
Reduce transaction duration:
-- Better: Shorter, focused transactions -- Read data SELECT data FROM large_table WHERE id = 123; -- [Process data outside transaction] -- Update in a brief transaction START TRANSACTION; UPDATE large_table SET processed = 1 WHERE id = 123; COMMIT;
-
Adjust isolation level:
-- Check current isolation level SELECT @@transaction_isolation; -- For read operations that don't need strong consistency SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Prevention
-
Access tables and rows in a consistent order in all transactions
-
Keep transactions short and focused:
- Don't include user interaction within transactions
- Process data between transactions when possible
-
Use proper indexes to reduce lock contention:
-- Add missing indexes CREATE INDEX idx_orders_customer_id ON orders(customer_id);
-
Monitor deadlocks to identify patterns:
-- Enable deadlock monitoring SET GLOBAL innodb_print_all_deadlocks = ON;