Introduction

MySQL InnoDB uses row-level locking to ensure transaction isolation and data consistency. When a transaction holds locks on rows and another transaction attempts to access those same rows, the second transaction waits for the locks to be released. If the waiting time exceeds the innodb_lock_wait_timeout setting (default 50 seconds), MySQL returns "Lock wait timeout exceeded" error. This commonly occurs with long-running transactions, poorly optimized queries that scan many rows, or concurrent access patterns that create lock contention. Understanding lock types, identifying blocking transactions, and optimizing access patterns is essential for resolving lock wait timeouts.

Symptoms

When MySQL lock wait timeout occurs, you will observe:

  • SQL queries fail with error code 1205
  • Application reports "Lock wait timeout exceeded; try restarting transaction"
  • Long-running transactions blocking other operations
  • Dashboard or report queries timing out
  • Batch jobs failing intermittently

MySQL error message: `` ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

In application logs: `` SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction

MySQL error log shows: `` [Warning] InnoDB: A long semaphore wait: --Thread 140123456789 has waited at buf0buf.cc line 123 for 51.00 seconds

Common Causes

  1. 1.Long-running transaction - Transaction holds locks for extended period
  2. 2.Uncommitted transaction - Transaction started but never committed
  3. 3.Lock contention hotspot - Multiple transactions competing for same rows
  4. 4.Table scans requiring locks - Full table scans lock many rows
  5. 5.Foreign key checks - FK constraints cause additional locking
  6. 6.Gap locks for inserts - Insert operations create gap locks
  7. 7.Deadlock not detected - Potential deadlock not caught by detector
  8. 8.Insufficient index - Query locks more rows than necessary
  9. 9.High concurrency - Too many simultaneous transactions
  10. 10.Slow queries in transaction - Slow queries extend lock duration

Step-by-Step Fix

Step 1: Identify Blocking Transactions

Find transactions currently holding locks:

sql
-- Check for transactions waiting for locks
SELECT 
    r.trx_id AS waiting_trx_id,
    r.trx_mysql_thread_id AS waiting_thread,
    r.trx_query AS waiting_query,
    b.trx_id AS blocking_trx_id,
    b.trx_mysql_thread_id AS blocking_thread,
    b.trx_query AS blocking_query,
    b.trx_started AS blocking_started,
    TIMESTAMPDIFF(SECOND, b.trx_started, NOW()) AS blocking_duration_seconds
FROM information_schema.innodb_lock_waits w
JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;

Check long-running transactions: ``sql -- Find transactions running longer than 10 seconds SELECT trx_id, trx_mysql_thread_id AS thread_id, trx_state, trx_started, TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS duration_seconds, trx_query, trx_rows_locked, trx_rows_modified FROM information_schema.innodb_trx WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 10 ORDER BY duration_seconds DESC;

View lock details: ``sql -- In MySQL 8.0+, use performance_schema SELECT OBJECT_NAME AS table_name, INDEX_NAME, LOCK_TYPE, LOCK_MODE, THREAD_ID, PROCESSLIST_ID, PROCESSLIST_INFO FROM performance_schema.data_locks WHERE OBJECT_SCHEMA = 'your_database';

Step 2: Check Current Lock Timeout Setting

Review the timeout configuration:

```sql -- Check lock wait timeout SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';

-- Check other relevant settings SHOW VARIABLES LIKE 'innodb_%lock%'; SHOW VARIABLES LIKE 'transaction%'; ```

Variable_nameValue
innodb_lock_wait_timeout50

Step 3: Examine Blocking Query

Identify what the blocking transaction is doing:

```sql -- Get the blocking thread's processlist info SELECT * FROM information_schema.processlist WHERE id = <blocking_thread_id>;

-- Show full processlist for all active queries SHOW FULL PROCESSLIST; ```

If blocking query is running: ``sql -- In MySQL 8.0+, see currently executing statement SELECT THREAD_ID, PROCESSLIST_ID, PROCESSLIST_USER, PROCESSLIST_HOST, PROCESSLIST_DB, PROCESSLIST_COMMAND, PROCESSLIST_TIME, PROCESSLIST_INFO, PROCESSLIST_STATE FROM performance_schema.threads WHERE PROCESSLIST_ID = <thread_id>;

Step 4: Kill Blocking Transaction (Immediate Fix)

If blocking transaction is stuck or runaway:

```sql -- First, identify the blocking thread SELECT trx_mysql_thread_id FROM information_schema.innodb_trx WHERE trx_id = <blocking_trx_id>;

-- Kill the blocking thread (use with caution!) KILL <thread_id>;

-- Or kill query but keep connection KILL QUERY <thread_id>; ```

From command line: ```bash # Get blocking thread IDs mysql -e "SELECT trx_mysql_thread_id FROM information_schema.innodb_trx WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 60;" -N

# Kill specific thread mysql -e "KILL 12345;" ```

Step 5: Increase Lock Wait Timeout

Adjust timeout for specific session or globally:

```sql -- For current session only SET SESSION innodb_lock_wait_timeout = 120;

-- Globally (affects new connections) SET GLOBAL innodb_lock_wait_timeout = 120;

-- Per transaction (MySQL 8.0+) SET @@SESSION.innodb_lock_wait_timeout = 120; START TRANSACTION; -- Your queries here COMMIT; ```

For permanent change, edit configuration: ``bash sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

Add: ``ini [mysqld] innodb_lock_wait_timeout = 120

Restart MySQL: ``bash sudo systemctl restart mysql

Step 6: Optimize Queries to Reduce Lock Time

Improve queries that hold locks too long:

Bad: Locking many rows during update ``sql -- This locks ALL rows matching condition UPDATE orders SET status = 'processed' WHERE status = 'pending';

Better: Process in smaller batches ``sql -- Process in batches of 1000 SET @batch_size = 1000; WHILE EXISTS (SELECT 1 FROM orders WHERE status = 'pending' LIMIT 1) DO UPDATE orders SET status = 'processed' WHERE status = 'pending' LIMIT @batch_size; COMMIT; -- Small delay to allow other transactions DO SLEEP(0.1); END WHILE;

Bad: Long transaction with multiple operations ``sql START TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- Many other operations... UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- Long pause here holds locks INSERT INTO transactions VALUES (...); COMMIT;

Better: Minimize transaction scope ``sql -- Keep transaction as short as possible START TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2; COMMIT; -- Do other work outside transaction INSERT INTO transactions VALUES (...);

Step 7: Add Indexes to Reduce Lock Scope

Missing indexes cause more rows to be locked:

```sql -- Check if proper indexes exist EXPLAIN SELECT * FROM orders WHERE customer_id = 123 AND status = 'pending';

-- If type is 'ALL' or 'range' with many rows, add index CREATE INDEX idx_orders_customer_status ON orders(customer_id, status);

-- Analyze table after adding index ANALYZE TABLE orders; ```

Step 8: Handle Foreign Key Locking

Foreign keys can cause additional locking:

```sql -- Check foreign key constraints SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = 'your_database';

-- Consider disabling FK checks for bulk operations SET FOREIGN_KEY_CHECKS = 0; -- Bulk operations SET FOREIGN_KEY_CHECKS = 1; ```

Step 9: Use Read Committed for Less Locking

If appropriate for your application:

```sql -- Check current isolation level SELECT @@GLOBAL.transaction_isolation, @@SESSION.transaction_isolation;

-- Set to READ COMMITTED (less locking than REPEATABLE READ) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- Or globally SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; ```

Verification

After implementing fixes, verify lock issues are resolved:

```sql -- Monitor for lock waits SELECT COUNT(*) AS lock_waits FROM information_schema.innodb_lock_waits; -- Should be 0 or minimal

-- Check for long transactions SELECT COUNT(*) AS long_transactions FROM information_schema.innodb_trx WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 10; -- Should be low

-- Monitor lock wait timeout errors SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_timeouts'; ```

Test queries that previously timed out: ``sql -- Test the problematic query SELECT ... FOR UPDATE; -- Should complete within timeout

Prevention

To prevent lock wait timeouts:

  1. 1.Keep transactions short:
  2. 2.```sql
  3. 3.-- Bad: Transaction spans user interaction
  4. 4.START TRANSACTION;
  5. 5.SELECT ... FOR UPDATE;
  6. 6.-- Wait for user input (BAD!)
  7. 7.UPDATE ...;
  8. 8.COMMIT;

-- Good: Transaction is atomic START TRANSACTION; UPDATE ...; COMMIT; ```

  1. 1.Use appropriate isolation levels:
  2. 2.```sql
  3. 3.-- READ COMMITTED for less locking
  4. 4.SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
  5. 5.`
  6. 6.Add indexes for queries that lock rows:
  7. 7.```sql
  8. 8.-- Ensure WHERE clause columns are indexed
  9. 9.CREATE INDEX idx_status ON orders(status);
  10. 10.`
  11. 11.Process in batches:
  12. 12.```sql
  13. 13.-- Don't lock entire table
  14. 14.DELETE FROM logs WHERE created_at < '2024-01-01' LIMIT 1000;
  15. 15.-- Repeat in loop
  16. 16.`
  17. 17.Monitor lock metrics:
  18. 18.```sql
  19. 19.-- Set up monitoring
  20. 20.SHOW GLOBAL STATUS LIKE 'Innodb_row_lock%';
  21. 21.`
  22. 22.Use optimistic locking:
  23. 23.```sql
  24. 24.-- Instead of SELECT FOR UPDATE
  25. 25.UPDATE products
  26. 26.SET stock = stock - 1, version = version + 1
  27. 27.WHERE id = 123 AND version = 5;
  28. 28.-- If affected rows = 0, version changed, retry
  29. 29.`
  30. 30.Set up alerts for long transactions:
  31. 31.```sql
  32. 32.-- Check periodically (e.g., every minute)
  33. 33.SELECT COUNT(*) FROM information_schema.innodb_trx
  34. 34.WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 30;
  35. 35.-- Alert if > 0
  36. 36.`
  • [Database troubleshooting: Fix Backup Exclusive Lock Table Production Writes ](backup-exclusive-lock-table-production-writes)
  • [Fix Connection Pool Leak Application Not Closing Issue in Database](connection-pool-leak-application-not-closing)
  • [Fix Connection Reset Idle Timeout Firewall Issue in Database](connection-reset-idle-timeout-firewall)
  • [Fix Connection Reset Idle Timeout Serverless Database Issue in Database](connection-reset-idle-timeout-serverless-database)
  • [Fix Connection String Encoding Special Characters Issue in Database](connection-string-encoding-special-characters)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "MySQL InnoDB Lock Wait Timeout", "description": "Fix MySQL InnoDB lock wait timeout errors. Identify blocking transactions, optimize queries, and tune lock timeout settings.", "url": "https://www.fixwikihub.com/fix-mysql-innodb-lock-wait-timeout", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2025-12-10T00:23:44.625Z", "dateModified": "2025-12-10T00:23:44.625Z" } </script>