MySQL Lock wait timeout exceeded: Troubleshooting & Resolution on CentOS Stream / Rocky Linux
Resolve 'MySQL Lock wait timeout exceeded' errors on CentOS Stream / Rocky Linux. Diagnose deadlocks, long-running transactions, and optimize InnoDB settings for robust database performance.
Resolve 'MySQL Lock wait timeout exceeded' errors on CentOS Stream / Rocky Linux. Diagnose deadlocks, long-running transactions, and optimize InnoDB settings for robust database performance.
The "Lock wait timeout exceeded" error in MySQL is a critical symptom indicating that a transaction has waited too long to acquire a lock on a row or table that is currently held by another transaction. From an end-user perspective, this often manifests as slow application responses, failed database operations, or generic "internal server errors" in web applications. For administrators, it signals underlying contention issues, inefficient queries, or suboptimal database configuration. This guide provides a systematic approach to diagnose and resolve this common database performance bottleneck on CentOS Stream and Rocky Linux environments.
Symptom & Error Signature
When this error occurs, applications typically log an error message, and MySQL itself may log relevant information to its error log. You might see variations depending on the application and database driver.
Typical Application/Client Error:
SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction
MySQL Error Log Entries (e.g., /var/log/mysqld.log):
[ERROR] [MY-011000] [Server] Failed to create a new thread for client connection: Can't create more than max_connections+1 threads
[ERROR] [MY-010091] [Server] Aborted connection 12345 to db: 'your_db' user: 'your_user' host: 'localhost' (Got an error writing communication packets)
[Note] [MY-011011] [Server] Error writing to master_binlog.00000X at offset Y.
While the latter two are general connection issues, they often accompany lock wait timeouts because the client connection is dropped after the database operation fails.
InnoDB Status Output Snippet (indicative of contention):
--- LATEST DETECTED DEADLOCK
...
*** (1) TRANSACTION:
TRANSACTION X ID 123456789 waiting for a lock on record, lock_mode X locks rec but not gap
...
*** (2) TRANSACTION:
TRANSACTION Y ID 987654321 waiting for a lock on record, lock_mode X locks rec but not gap
...
*** WE ROLL BACK TRANSACTION (1)
While this specific snippet points to a deadlock, prolonged LOCK WAIT states in the TRANSACTIONS section without a LATEST DETECTED DEADLOCK can lead to the timeout.
Root Cause Analysis
The "Lock wait timeout exceeded" error primarily arises from contention over shared resources within the InnoDB storage engine. Understanding the underlying causes is crucial for effective resolution:
- Long-Running Transactions: A transaction that holds locks (row-level or table-level) for an extended period prevents other transactions from accessing or modifying the locked data. This is often due to complex operations, large data sets, or inefficient application logic.
- Deadlocks: Although InnoDB has sophisticated deadlock detection and typically rolls back one of the transactions to resolve it, in some scenarios, transactions might wait for locks until the
innodb_lock_wait_timeoutis hit before a deadlock is detected or if the locking pattern is particularly complex. - Inefficient Queries: Queries lacking proper indexes, performing full table scans on large tables, or involving complex joins can acquire more locks than necessary or hold them for longer durations, increasing the likelihood of contention.
- High Concurrency & Write-Heavy Workloads: In environments with a large number of concurrent connections performing frequent write (INSERT, UPDATE, DELETE) operations, the probability of multiple transactions trying to access the same rows simultaneously increases significantly.
- Suboptimal
innodb_lock_wait_timeoutSetting: The defaultinnodb_lock_wait_timeoutis 50 seconds. While generally reasonable, if application transactions naturally require slightly longer periods to complete, or if the system is frequently under heavy load, this default might be too aggressive, leading to premature timeouts. - Application Logic Errors: Transactions that are opened but not properly committed or rolled back (e.g., due to an application crash or unhandled exception) can leave locks open indefinitely until the session terminates, blocking other operations. Similarly, inconsistent lock acquisition order across different parts of an application can exacerbate deadlocks.
- Hardware/I/O Bottlenecks: Slow disk I/O can significantly prolong the duration of transactions, especially those involving writes or reading large data sets from disk, thereby increasing the time locks are held. This can make a system more susceptible to lock wait timeouts even with otherwise efficient queries.
Step-by-Step Resolution
Addressing the "Lock wait timeout exceeded" error requires a methodical approach, often involving a combination of diagnostic steps, configuration adjustments, and code optimizations.
1. Analyze InnoDB Status for Active Transactions and Locks
The SHOW ENGINE INNODB STATUS command is your most powerful tool for real-time InnoDB diagnostics.
mysql -u root -p
mysql> SHOW ENGINE INNODB STATUSG
Look for the following sections:
TRANSACTIONS: Identifies active transactions, their state (RUNNING,LOCK WAIT), and which locks they are waiting for or holding. Pay close attention to transactions inLOCK WAITstate, noting the(ID ...)andwaiting for a lock on record, lock_mode X locks rec but not gapdetails. This shows the exact resource being contended.LATEST DETECTED DEADLOCK: While the primary error is a timeout, frequent deadlocks can contribute. This section will detail the transactions involved and the specific locks.SEMAPHORES: High semaphore waits can indicate CPU contention or issues with mutexes/latches.ROW LOCKS: Provides statistics on row lock waits.
Additionally, use SHOW PROCESSLIST to identify currently running queries and their states:
mysql> SHOW FULL PROCESSLISTG
- Look for processes with
Timecolumns indicating long-running queries. - Pay attention to the
Statecolumn forLocked,Waiting for table metadata lock,Sending data, orSorting resulton large datasets. - Identify the
Idof any suspicious processes.
2. Identify and Optimize Problematic Queries
Inefficient queries are a primary cause of extended lock durations.
a. Enable and Analyze Slow Query Log:
Edit your MySQL configuration file (e.g., /etc/my.cnf or /etc/mysql/conf.d/mysql.cnf on CentOS/Rocky Linux).
sudo vi /etc/my.cnf
Add or modify these lines in the [mysqld] section:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql-slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
After modifying
my.cnf, you must restart MySQL:sudo systemctl restart mysqldMonitor
/var/log/mysql-slow.logfor queries exceedinglong_query_time.
b. Use EXPLAIN to Optimize Queries:
Once you identify slow or problematic queries from logs or SHOW FULL PROCESSLIST, use EXPLAIN to analyze their execution plan.
mysql> EXPLAIN SELECT column1, column2 FROM your_table WHERE condition_column = 'value';
Look for:
type:ALL(full table scan) is often bad for large tables. Aim forref,eq_ref,range,const,system.rows: The number of rows MySQL estimates it has to examine.Extra:Using filesort,Using temporaryindicate potential performance issues.
c. Create/Optimize Indexes:
Based on EXPLAIN output, add appropriate indexes to columns used in WHERE clauses, JOIN conditions, ORDER BY, and GROUP BY.
mysql> CREATE INDEX idx_condition_column ON your_table (condition_column);
3. Adjust innodb_lock_wait_timeout
This parameter defines how long an InnoDB transaction waits for a row lock before timing out and rolling back. The default is 50 seconds.
a. Temporarily Increase (Session/Global):
To test the impact without restarting MySQL:
mysql> SET GLOBAL innodb_lock_wait_timeout = 120; -- For new connections
mysql> SET SESSION innodb_lock_wait_timeout = 120; -- For current connection
b. Permanently Increase:
Edit your MySQL configuration file (/etc/my.cnf or a custom .cnf file in /etc/mysql/conf.d/).
sudo vi /etc/my.cnf
Add or modify in the [mysqld] section:
[mysqld]
innodb_lock_wait_timeout = 120
Increasing
innodb_lock_wait_timeoutshould be a temporary measure or a last resort if other optimizations don't fully resolve the issue. A higher timeout means transactions will wait longer, potentially leading to application unresponsiveness. The root cause (long-held locks) should still be addressed.
After saving, restart MySQL:
sudo systemctl restart mysqld
4. Review and Optimize Application Transaction Logic
Application code often plays a significant role in database contention.
- Minimize Transaction Scope: Keep transactions as short as possible. Commit frequently. Don't include operations that don't require transactional integrity within a transaction.
- Consistent Lock Acquisition Order: If multiple tables/rows are locked within a transaction, always acquire locks in the same order across all transactions to prevent deadlocks.
- Use
SELECT ... FOR UPDATEJudiciously: This explicitly locks selected rows for the duration of the transaction. Use it only when necessary to prevent race conditions during updates. - Implement Retry Logic: For operations prone to lock wait timeouts, implement graceful retry mechanisms in your application code. This allows the application to re-attempt a transaction that failed due to a transient lock issue.
5. Optimize innodb_buffer_pool_size and I/O Performance
The innodb_buffer_pool_size is the most critical memory setting for InnoDB. It caches data and indexes, significantly reducing disk I/O.
a. Adjust innodb_buffer_pool_size:
Edit your MySQL configuration file (/etc/my.cnf).
sudo vi /etc/my.cnf
Add or modify in the [mysqld] section:
[mysqld]
innodb_buffer_pool_size = 70-80%_of_RAM
For a dedicated database server, allocate 70-80% of the total available RAM to
innodb_buffer_pool_size. For example, on a server with 16GB RAM, set it to12Gor13G. Leave enough RAM for the OS and other processes.innodb_buffer_pool_size = 12G # Example for a 16GB RAM server
Restart MySQL after making changes:
sudo systemctl restart mysqld
b. Monitor and Optimize Disk I/O:
- Use tools like
iostat -x 5oratopto monitor disk I/O performance. Look for highutil(utilization), highawait(average wait time), and highsvctm(service time). - Ensure your storage is fast (SSDs/NVMe drives are highly recommended for database servers).
- Consider separating data and logs onto different physical drives if I/O is a persistent bottleneck.
6. Identify and Kill Blocking Processes (Emergency)
In an emergency, if a single query is clearly blocking many others and causing widespread timeouts, you might need to terminate it.
- Identify the process ID (ID column) using
SHOW FULL PROCESSLIST;. - Use the
KILLcommand:
mysql> KILL <Process_ID>;
Use
KILLwith extreme caution. Killing an active transaction will cause it to roll back, potentially leading to data inconsistency if your application is not designed to handle such events gracefully. This is a temporary measure to alleviate immediate pressure and not a solution to the underlying problem.
7. Upgrade MySQL/MariaDB
Newer versions of MySQL and MariaDB often come with significant performance improvements, better concurrency handling, and enhanced deadlock detection algorithms. While not a direct fix for application-level issues, ensuring your database server is running a modern, stable version can contribute to overall stability and performance. For example, MySQL 8.x and MariaDB 10.x include numerous optimizations compared to older versions. Always plan upgrades carefully, test thoroughly, and back up your data.
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.