The MySQL server is consuming an excessive amount of RAM, leading to system instability and performance degradation.
Common Causes and Fixes:
1. Insufficient innodb_buffer_pool_size:
- Diagnosis: Check current memory usage with
free -hand compare it toinnodb_buffer_pool_sizein yourmy.cnf(ormy.ini). A common rule of thumb is to setinnodb_buffer_pool_sizeto 50-75% of your total system RAM on a dedicated database server. - Fix: Edit
my.cnf(typically located at/etc/mysql/my.cnf,/etc/my.cnf, or/etc/mysql/mysql.conf.d/mysqld.cnf). Find the[mysqld]section and adjustinnodb_buffer_pool_size. For example, on a 16GB RAM server, you might set:
Restart MySQL:innodb_buffer_pool_size = 10Gsudo systemctl restart mysql(ormysqld). - Why it works: The InnoDB buffer pool caches data and indexes in memory. If it’s too small, MySQL constantly has to fetch data from disk, leading to high I/O and often increased CPU usage, which can indirectly appear as high memory usage due to caching of frequently accessed data blocks that don’t fit.
2. Large tmp_table_size and max_heap_table_size:
- Diagnosis: Monitor
Created_tmp_tablesandCreated_tmp_disk_tablesstatus variables:SHOW GLOBAL STATUS LIKE 'Created_tmp%';. IfCreated_tmp_disk_tablesis a significant fraction ofCreated_tmp_tables, complex queries are spilling to disk, which is inefficient and can indirectly consume memory. - Fix: Increase
tmp_table_sizeandmax_heap_table_sizeinmy.cnfwithin the[mysqld]section. These should generally be set to the same value. For example:
Restart MySQL.tmp_table_size = 256M max_heap_table_size = 256M - Why it works: These settings control the maximum size of in-memory temporary tables. If a temporary table exceeds
tmp_table_size(ormax_heap_table_sizeif it’s a MEMORY storage engine table), it’s converted to an on-disk table, which is much slower. While this is primarily about disk I/O, the creation and management of large in-memory temporary tables before they spill can consume significant RAM.
3. Excessive sort_buffer_size and join_buffer_size:
- Diagnosis: High values for these per-session buffers, especially with many concurrent connections, can lead to substantial memory consumption. There isn’t a direct status variable for current usage, but if you’ve recently increased them and see memory spikes, this is a likely culprit.
- Fix: Reduce
sort_buffer_sizeandjoin_buffer_sizeinmy.cnfunder[mysqld]. The default values are often sufficient. For example, try:
Restart MySQL.sort_buffer_size = 2M join_buffer_size = 1M - Why it works: These buffers are allocated per thread that needs them. A large
sort_buffer_sizeis used for operations likeORDER BYorGROUP BYthat can’t use an index, andjoin_buffer_sizeis used for joins that can’t use an index. If you have hundreds of connections performing such operations simultaneously, the memory allocated for these buffers can multiply rapidly.
4. Large max_connections with low thread_cache_size:
- Diagnosis: Check
max_connectionsinmy.cnfand the current number of active connections (SHOW GLOBAL STATUS LIKE 'Threads_connected';). Ifmax_connectionsis very high (e.g., >500) and the server is under load, many threads might be created and destroyed frequently, or simply held open. - Fix: Adjust
max_connectionsto a reasonable number based on your application’s needs and server resources. Also, increasethread_cache_sizeto allow MySQL to reuse threads. For example, if you typically have 100-200 active connections:
Restart MySQL.max_connections = 200 thread_cache_size = 20 - Why it works: Each connection consumes some memory. A very high
max_connectionssetting, especially if not fully utilized, can be a misconfiguration.thread_cache_sizehelps by keeping a pool of ready-to-use threads, reducing the overhead of thread creation and destruction, which itself consumes memory and CPU.
5. Query Cache (if enabled and misconfigured):
- Diagnosis: If you’re on an older MySQL version (prior to 8.0 where it was removed) and have
query_cache_typeenabled, it can consume memory. CheckSHOW GLOBAL STATUS LIKE 'Qcache%';. High numbers forQcache_queries_in_cacheandQcache_free_memorycan indicate it’s being used, but also that it might be fragmented or too small. - Fix: For MySQL versions where it exists, it’s generally recommended to disable the query cache for most modern workloads. In
my.cnf:
Restart MySQL.query_cache_type = 0 query_cache_size = 0 - Why it works: The query cache stores the results of
SELECTstatements. While intended to speed up identical queries, it has significant overhead for invalidation and memory management, especially with frequent writes. Disabling it removes this memory overhead and often improves performance on write-heavy or complex query workloads.
6. Other Per-Session Buffers:
- Diagnosis: Similar to
sort_buffer_sizeandjoin_buffer_size, buffers likeread_buffer_sizeandread_rnd_buffer_sizeare allocated per thread. If these are set excessively high, memory usage can climb. - Fix: Reduce these values in
my.cnfunder[mysqld]. Defaults are usually fine.
Restart MySQL.read_buffer_size = 128K read_rnd_buffer_size = 256K - Why it works: These are used for sequential reads (
read_buffer_size) and reading rows after sorting or aORDER BYthat doesn’t use an index (read_rnd_buffer_size). Like other per-session buffers, their memory impact is multiplied by the number of active connections.
After fixing these common issues, the next error you might encounter is related to open_files_limit if your increased buffer sizes and connection counts require more file descriptors, or a Too many connections error if max_connections is still too low for your application’s peak load.