Fix MySQL Deadlock Found When Trying to Get Lock: Root Causes and Minimal Checks

Topic: mysql-deadlock-found-when-trying-to-get-lockUpdated 7/20/2026

Quick Answer

  • Conclusion: MySQL deadlock errors (SQLSTATE 40001) are normal InnoDB behavior that requires application-level retry logic, not a server restart. The fix involves implementing exponential-backoff retries and optimizing lock ordering.
  • First checks: Run SHOW ENGINE INNODB STATUS immediately after a deadlock to identify the conflicting transactions. Check that all transactions acquire locks in the same order across your application.
  • Minimal fix: Add retry logic with exponential backoff (e.g., 3 retries with 100ms base delay) around your transaction code. Ensure all SQL statements within a transaction use indexed columns for WHERE clauses.
  • Environment boundary: This solution applies to MySQL/InnoDB with concurrent write workloads. Not needed for read-only queries or low-concurrency systems.

What Problem It Solves

MySQL deadlock errors occur when two or more transactions hold locks that the other needs, creating a circular dependency. InnoDB automatically detects this condition and rolls back one transaction (the "victim"), returning error 1213: Deadlock found when trying to get lock; try restarting transaction. This error is common in high-concurrency write scenarios such as:

  • E-commerce order processing and inventory deduction
  • Payment transaction flows
  • Account balance updates
  • Queue or job processing systems

The solution provides a systematic approach to diagnose, handle, and prevent deadlocks in production environments.

Root Cause Analysis

Deadlocks in InnoDB happen when:

  1. Inconsistent lock order: Transaction A locks row 1 then row 2, while Transaction B locks row 2 then row 1
  2. Missing indexes: Without proper indexes, InnoDB uses table-level locks or gap locks that cover more rows than necessary
  3. Long-running transactions: Holding locks for extended periods increases collision probability
  4. Concurrent updates on overlapping row sets: Multiple transactions modifying the same rows simultaneously

To diagnose a specific deadlock:

SQL
SHOW ENGINE INNODB STATUS;

Look for the LATEST DETECTED DEADLOCK section, which shows:

  • The two transactions involved
  • The locks each transaction holds
  • The lock each transaction is waiting for
  • The victim transaction that was rolled back

Minimal Working Configuration

Application-Level Retry Logic

The most critical fix is implementing retry logic in your application. Here's a minimal Python example using exponential backoff:

PYTHON
import time
import mysql.connector
from mysql.connector.errors import DatabaseError

def execute_with_retry(cursor, sql, params=None, max_retries=3, base_delay=0.1):
    for attempt in range(max_retries):
        try:
            cursor.execute(sql, params)
            return
        except DatabaseError as e:
            if e.errno == 1213:  # Deadlock error code
                if attempt == max_retries - 1:
                    raise
                delay = base_delay * (2 ** attempt)
                time.sleep(delay)
            else:
                raise

For Spring Boot applications, use the @Retryable annotation:

JAVA
@Retryable(
    value = {DeadlockLoserDataAccessException.class},
    maxAttempts = 3,
    backoff = @Backoff(delay = 100, multiplier = 2)
)
public void updateInventory(Long productId, int quantity) {
    // transaction logic
}

Database Configuration

Enable deadlock logging for diagnostics:

SQL
SET GLOBAL innodb_print_all_deadlocks = ON;

Monitor the deadlock counter:

SQL
SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks';

Common Errors and Fixes

ErrorSQLSTATESolution
Deadlock found when trying to get lock; try restarting transaction40001Implement retry logic with exponential backoff. Check lock ordering across all transactions. Use SHOW ENGINE INNODB STATUS to diagnose.
Lock wait timeout exceeded; try restarting transaction1205Increase innodb_lock_wait_timeout (default 50s) or optimize transactions to reduce lock hold time. Check for long-running blocking transactions.
Table 'table_name' is full1114Check disk space and table space limits. Ensure innodb_data_file_path is configured adequately or enable auto-extend.
Cannot add foreign key constraint1215Ensure foreign key columns have indexes and matching data types/character sets. Verify parent table has corresponding records.

Production Notes and Security Checks

Critical Limitations

  1. Idempotency required: Deadlock retries may cause duplicate operations. Design your transaction logic to be idempotent (e.g., use INSERT ... ON DUPLICATE KEY UPDATE or check existence before insert).
  2. Latency trade-off: Exponential backoff increases response time under high contention. Monitor p99 latency after implementing retries.
  3. Index overhead: Adding indexes reduces lock contention but increases write operation overhead. Balance based on your read/write ratio.
  4. Team discipline: Lock ordering must be consistently applied across all application code. Document and enforce the order in code reviews.

Security Recommendations

  1. Minimal database privileges: Grant only necessary table-level permissions (SELECT, INSERT, UPDATE, DELETE) to application users. Avoid DDL privileges.
  2. Monitor deadlock rate: Set up alerts on Innodb_deadlocks counter. A sudden increase indicates a code or schema issue.
  3. Enable deadlock logging: Keep innodb_print_all_deadlocks = ON in production for forensic analysis.
  4. Avoid external calls in transactions: Never make HTTP requests or other external calls inside a database transaction. This dramatically increases lock hold time.
  5. Regular index audit: Periodically review index usage with SHOW INDEX FROM table_name and EXPLAIN for slow queries.

Index Optimization Example

Without proper indexes, a simple UPDATE can lock many rows:

SQL
-- Problem: No index on status column, locks entire table
UPDATE orders SET status = 'shipped' WHERE status = 'pending';

-- Fix: Add index on status column for precise row locking
CREATE INDEX idx_orders_status ON orders(status);

FAQ

Q: Do I need to restart MySQL after a deadlock?

A: No. Deadlocks are normal InnoDB behavior. MySQL automatically detects and rolls back one transaction (the victim). Restarting the server disconnects all clients and causes more problems. The correct approach is: 1) Ensure your application has retry logic; 2) Diagnose with SHOW ENGINE INNODB STATUS; 3) Optimize lock ordering or add indexes.

Q: How do I distinguish between deadlock and lock wait timeout?

A: Deadlock (error 1213, SQLSTATE 40001) is a circular wait condition that InnoDB detects immediately and resolves by rolling back one transaction. Lock wait timeout (error 1205, SQLSTATE 1205) occurs when one transaction waits for another to release a lock beyond innodb_lock_wait_timeout (default 50 seconds). Deadlocks require lock ordering fixes; lock wait timeouts need shorter transactions or increased timeout settings.

Q: Why does adding indexes reduce deadlocks?

A: Without indexes, InnoDB uses table-level locks or gap locks that cover many rows, increasing lock conflict probability. With proper indexes, queries can lock only the matching rows (row-level locks), reducing the lock footprint. For example, UPDATE orders WHERE status='pending' without an index locks the entire table; with an index on status, only matching rows are locked.

Related Guides