📑 Daftar Isi
- MySQL Load 500% — What Does It Actually Mean?
- 80 Cores, 256GB RAM — Why Is MySQL Still Struggling?
- Reviewing the MySQL Config
- Tweaking MySQL Configuration
- 1. innodb_buffer_pool_size — Still Way Too Small
- 2. max_connections & Thread Cache
- 3. table_open_cache & table_definition_cache
- 4. tmp_table_size & max_heap_table_size
- 5. open_files_limit
- 6. Additional InnoDB I/O Optimizations
- 7. Timeout & Safety Settings
- Recommended MySQL Config — Final Version
- Monitoring & Verification After Changes
- Pro Tips & Warnings
- FAQ
- Q: Is it safe to set innodb_buffer_pool_size to 128GB on a 256GB RAM server right away?
- Q: After restarting MySQL with the new config, why did the website feel slightly slower at first?
- Q: Can I use this config for smaller VPS instances, like 8GB or 16GB RAM?
- Q: I applied this config but load is still high. What should I do next?
- Related Articles
I still remember that night — 2 AM, phone ringing non-stop, monitoring alerts flooding in from every direction. MySQL load average had spiked to 500%, and all the websites we managed were going down one by one. I SSH’d into the server immediately, ran top, and sure enough — the mysqld process was hogging all the CPU like it owned the place. What really got me was the server specs: 80 CPU cores and 256GB of RAM. How on earth could MySQL hit 500% load on hardware this powerful?
Imagine you have a beautiful 10-lane highway, wide and smooth, but then 500 cars try to squeeze through a single-lane entrance ramp at the same time. Total gridlock, right? That’s exactly what happens with MySQL on an unoptimized server — it’s not the highway that’s the problem, it’s the on-ramp configuration. MySQL on a big server without proper config tuning is like that 10-lane highway with a single-lane toll booth.
MySQL Load 500% — What Does It Actually Mean?
Before we dive into the config analysis, let’s get one thing straight — a 500% load average means there are roughly 5 times more processes waiting for CPU time than there are available cores. On an 80-core server, that’s around 400 processes stuck in the queue, waiting their turn. That’s not a small issue.
Here are the symptoms you’ll typically see when MySQL load spirals out of control:
- Websites become extremely slow — page load times jump from the usual 200ms to 5-10 seconds or more
- “Too many connections” errors appearing in MySQL error logs
- Server load average spikes — climbing from the normal 10-20 range to 400+
- Simple queries take forever — a basic SELECT that should take milliseconds suddenly takes seconds
- Sleeping processes pile up in SHOW PROCESSLIST output
- Swap usage increases — even though there’s plenty of free RAM available
If you see all these symptoms appearing together, the root cause is almost certainly a MySQL configuration that hasn’t been tuned for your actual server specifications. This is an incredibly common issue on shared hosting servers and VPS instances that have lots of RAM but still run a default or outdated MySQL config.
80 Cores, 256GB RAM — Why Is MySQL Still Struggling?
This is the mystery that trips up a lot of server administrators. How can a server with monster specs like these have MySQL performance problems? Shouldn’t hardware this powerful handle anything you throw at it?
The answer is simple: hardware doesn’t determine MySQL performance — configuration does.
MySQL has dozens of parameters that control how it uses the resources available to you. If you don’t configure these parameters properly, MySQL will artificially limit itself even when CPU and RAM are sitting idle. It’s like having a Ferrari with the accelerator capped at 30 km/h.
The most common bottleneck parameters include:
- innodb_buffer_pool_size — If too small, MySQL has to read data from disk constantly, which is orders of magnitude slower than RAM
- max_connections — If too small, new connections get rejected even though the server has plenty of capacity
- table_open_cache — If too small, MySQL has to repeatedly open and close table files, which is extremely expensive
- tmp_table_size — If too small, MySQL is forced to use disk for temporary tables, which kills performance on complex queries
This is exactly what was happening on the server in question — the MySQL config was either using defaults or had settings from an older, smaller server. The result was MySQL barely using a fraction of the 256GB RAM available.
Reviewing the MySQL Config
Now let’s dissect the config that was applied. I’ll analyze each section and point out what’s already correct and what still needs tweaking.
The current config:
[mysqld]
# Logging
log-error = /var/lib/mysql/server-01.err
# Performance
performance-schema = 0
# Buffer pool
innodb_buffer_pool_size = 5G
innodb_file_per_table = 1
# Connections
max_connections = 1024
max_allowed_packet = 256M
open_files_limit = 80000
# Storage engine
default-storage-engine = InnoDB
# Query cache disabled
query_cache_type = 0
query_cache_size = 0
query_cache_limit = 0
key_buffer_size = 32M
# Timeouts
wait_timeout = 30
interactive_timeout = 30
# Table caching
table_open_cache = 4096
table_definition_cache = 4096
# Max execution time
max_statement_time = 30
# Temp tables
tmp_table_size = 128M
max_heap_table_size = 128M
# InnoDB tweaks
innodb_stats_on_metadata = 0
innodb_flush_method = O_DIRECT
What’s Already Correct
query_cache_type = 0 — This is correct. Query Cache has been deprecated since MySQL 5.7 and frequently causes lock contention issues on servers with many connections. Disabling it is the right call.
innodb_flush_method = O_DIRECT — Good. This prevents double buffering with the OS page cache, meaning InnoDB writes directly to disk. This is the right choice for servers with dedicated storage.
innodb_stats_on_metadata = 0 — Correct. This prevents MySQL from recalculating statistics every time you run SHOW STATUS, which can cause query plans to fluctuate unpredictably.
wait_timeout = 30 — Already aggressive enough and good for shared hosting. Idle connections won’t pile up.
innodb_file_per_table = 1 — Standard best practice. Each table gets its own .ibd file, making maintenance much easier.
What Needs to Change
This is where the real problems lie. Several settings are far too small for a server with 256GB of RAM and 80 CPU cores.
Tweaking MySQL Configuration
1. innodb_buffer_pool_size — Still Way Too Small
This is the single most critical parameter in MySQL performance tuning. Currently set to 5GB, but the server has 256GB of RAM. That means you’re only using about 2% of your total RAM for the InnoDB buffer pool.
The InnoDB Buffer Pool is where MySQL stores data and index pages in RAM so it doesn’t have to read from disk on every query. The larger the buffer pool, the more data stays in memory, and the faster your queries execute.
Recommendation: For a dedicated MySQL server, the buffer pool should ideally be 60-70% of total RAM. For a shared hosting server that also runs a web server and other services, starting at 50-60% of RAM is appropriate.
For a 256GB RAM server that also runs LiteSpeed and other services:
# For 256GB RAM dedicated to MySQL:
innodb_buffer_pool_size = 160G
# For 256GB RAM shared hosting
(with LiteSpeed, etc.):
innodb_buffer_pool_size = 128G
With a 128GB buffer pool, virtually all your active data can fit in RAM. This will dramatically reduce disk I/O and bring the load average down significantly.
Warning: Don’t jump straight to an enormous buffer pool without testing. Start at 128G, monitor for a few days, then increase gradually if there’s still headroom. An oversized buffer pool can cause swapping, which actually makes things worse.
2. max_connections & Thread Cache
max_connections = 1024 is generally sufficient for most scenarios. What people often overlook is thread_cache_size. It’s not defined in the current config, which means MySQL falls back to its typically tiny default value.
The thread cache exists so MySQL doesn’t need to create a brand new thread every time a new connection comes in. On a shared hosting server with many connections, this saves significant overhead.
# Add these:
thread_cache_size = 64
table_open_cache_instances = 16
With 80 CPU cores, table_open_cache_instances = 16 allows MySQL to access the table cache in parallel without contention. This is critical for performance on multi-core servers.
3. table_open_cache & table_definition_cache
Currently set to 4096, which is adequate for servers with a few hundred databases. But for a shared hosting server with many databases and tables, you can increase this:
# For servers with many databases
table_open_cache = 16384
table_definition_cache = 16384
How to check if your table_open_cache is large enough:
mysql -e "SHOW GLOBAL STATUS LIKE 'Open_tables';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Opened_tables';"
If Opened_tables keeps climbing rapidly, your table_open_cache is too small. Ideally, the ratio of Opened_tables per day should be as low as possible. If it reaches hundreds of thousands per day, you need to increase table_open_cache.
4. tmp_table_size & max_heap_table_size
Currently set to 128MB. For a 256GB RAM server, this can be increased significantly. Temporary tables are used by MySQL when executing complex queries involving JOINs, GROUP BY, or ORDER BY on large datasets.
# Increase for complex queries
tmp_table_size = 512M
max_heap_table_size = 512M
With 512MB, MySQL can fit many more temporary tables in RAM without spilling to disk. This helps enormously with analytical queries or reports that are commonly run on shared hosting servers.
Important note: tmp_table_size and max_heap_table_size should be set to the SAME value. MySQL uses whichever is smaller.
5. open_files_limit
80000 is already quite high, but make sure the OS is actually allowing this limit. Check at the system level:
# Check file descriptor limits at OS level
cat /proc/$(pgrep -o mysqld)/limits | grep "Max open files"
If Max open files is below 80000, you need to increase the limit at the OS level too. On systemd-based systems:
# Add to /etc/systemd/system/mysqld.service.d/override.conf
[Service]
LimitNOFILE=100000
# Then reload
systemctl daemon-reload
systemctl restart mysqld
6. Additional InnoDB I/O Optimizations
innodb_flush_method = O_DIRECT is already correct. But here are some additional I/O parameters that can help significantly:
# I/O optimization for NVMe/SSD
innodb_io_capacity = 4000
innodb_io_capacity_max = 8000
innodb_read_io_threads = 16
innodb_write_io_threads = 16
innodb_flush_log_at_trx_commit = 2
innodb_log_file_size = 2G
innodb_log_buffer_size = 256M
innodb_flush_log_at_trx_commit = 2 — This is a trade-off between data safety and performance. With this setting, MySQL flushes the log to disk every second instead of on every commit. It’s much faster but there’s a risk of losing up to 1 second of the last transactions if the server crashes. For shared hosting that isn’t processing financial transactions, this trade-off is absolutely worth it.
innodb_io_capacity — Match this to your storage capability. For NVMe: 4000-10000. For SSD: 1000-4000. For HDD: 200-400.
7. Timeout & Safety Settings
# Add safety timeouts
lock_wait_timeout = 10
connect_timeout = 10
# Disable DNS resolution for faster connections
skip-name-resolve
lock_wait_timeout = 10 ensures that if a query is waiting for a lock too long, it gets cancelled after 10 seconds. This prevents a single rogue query from holding resources for an extended period.
skip-name-resolve eliminates DNS lookups for connecting clients, which can significantly reduce connection overhead on servers with many clients.
Recommended MySQL Config — Final Version
Based on the analysis above, here’s the MySQL configuration I recommend for an 80-core, 256GB RAM server running shared hosting with LiteSpeed:
[client-server]
!includedir /etc/my.cnf.d
[mysqld]
# Logging
log-error = /var/lib/mysql/server-01.err
# Performance Schema (disabled to save resources)
performance-schema = 0
# ===== BUFFER POOL =====
# For 256GB RAM server (shared hosting)
innodb_buffer_pool_size = 128G
innodb_buffer_pool_instances = 32
innodb_file_per_table = 1
# ===== CONNECTIONS =====
max_connections = 1024
thread_cache_size = 64
max_allowed_packet = 256M
# ===== FILE HANDLING =====
open_files_limit = 100000
table_open_cache = 16384
table_definition_cache = 16384
table_open_cache_instances = 16
# ===== STORAGE ENGINE =====
default-storage-engine = InnoDB
# ===== SQL MODE =====
sql_mode = "ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
# ===== QUERY CACHE (DISABLED) =====
query_cache_type = 0
query_cache_size = 0
query_cache_limit = 0
key_buffer_size = 32M
# ===== TIMEOUTS =====
wait_timeout = 30
interactive_timeout = 30
max_statement_time = 30
lock_wait_timeout = 10
connect_timeout = 10
# ===== TEMP TABLES =====
tmp_table_size = 512M
max_heap_table_size = 512M
# ===== INNODB TWEAKS =====
innodb_stats_on_metadata = 0
innodb_flush_method = O_DIRECT
innodb_io_capacity = 4000
innodb_io_capacity_max = 8000
innodb_read_io_threads = 16
innodb_write_io_threads = 16
innodb_flush_log_at_trx_commit = 2
innodb_log_file_size = 2G
innodb_log_buffer_size = 256M
# ===== SAFETY =====
skip-name-resolve
Monitoring & Verification After Changes
After you apply the config above and restart MySQL, don’t pop the champagne just yet — you need to monitor for several days to make sure everything is stable.
Here are the essential monitoring commands you should run:
# 1. Check MySQL status after restart
mysqladmin -u root -p status
# 2. Check buffer pool hit ratio
# (should be above 99% for optimal performance)
mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';"
# Hit ratio = 1 - (reads / read_requests)
# If above 99%, your buffer pool is large enough
# 3. Check for slow queries
mysql -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';"
# 4. Check connections vs max
mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected';"
mysql -e "SHOW GLOBAL VARIABLES LIKE 'max_connections';"
# 5. Check table cache hit ratio
mysql -e "SHOW GLOBAL STATUS LIKE 'Open_tables';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Opened_tables';"
# 6. Monitor swap usage — should be minimal
free -m
# 7. Monitor InnoDB row operations
mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_rows_%';"
| Metric | Target | What Happens If Not Met |
|---|---|---|
| Innodb Buffer Pool Hit Ratio | > 99% | High disk reads, load increases |
| Threads_connected | < 80% of max_connections | Risk of connection exhaustion |
| Slow_queries | Minimal | Queries need indexing |
| Swap usage | < 100MB | Buffer pool may be too large |
| Opened_tables | Stable / low daily count | table_open_cache too small |
Pro Tips & Warnings
From my experience managing hundreds of servers, here are some frequently overlooked tips:
- Never restart MySQL during peak hours — Apply config changes during low traffic, ideally late at night. The buffer pool needs time to warm up after a restart, so if you restart during high traffic, performance will temporarily degrade.
- Monitor for 24-48 hours before making further changes — After applying new config, don’t immediately tweak more parameters. Let MySQL stabilize first.
- innodb_buffer_pool_size must be divisible by innodb_buffer_pool_instances — If you set 32 instances, the buffer pool must divide evenly. 128G / 32 = 4GB per instance, which is very reasonable.
- Use innodb_flush_log_at_trx_commit = 2 wisely — It’s safe for shared hosting, but NEVER use it for applications processing financial transactions. For payment gateways, stick with setting 1.
- Check slow query logs — After config optimization, make sure there aren’t slow queries caused by missing indexes:
# Enable slow query log
mysql -e "SET GLOBAL slow_query_log = 'ON';"
mysql -e "SET GLOBAL long_query_time = 2;"
mysql -e "SET GLOBAL slow_query_log_file =
'/var/log/mysql/slow-query.log';"
# After a few days, check the log
grep -c "Query_time" /var/log/mysql/slow-query.log
- Backup your config before making changes — Always save a copy of the old config. If something goes wrong, you can roll back immediately:
cp /etc/my.cnf /etc/my.cnf.bak.$(date +%Y%m%d)
cp /etc/my.cnf.d/mysqld.cnf /etc/my.cnf.d/mysqld.cnf.bak.$(date +%Y%m%d)
FAQ
Q: Is it safe to set innodb_buffer_pool_size to 128GB on a 256GB RAM server right away?
You can, but I recommend taking a gradual approach. Start with 96GB, monitor for a few days, then increase to 128GB. The key is making sure enough RAM remains for the OS, LiteSpeed, and other services. Ideally, leave at least 20-30GB of RAM for the operating system and non-MySQL services. If your server also runs LiteSpeed with many sites, start with 110GB and monitor from there.
Q: After restarting MySQL with the new config, why did the website feel slightly slower at first?
This is normal and is called “buffer pool warming.” After a restart, MySQL’s buffer pool is empty — all data has to be re-read from disk. This process takes anywhere from a few minutes to several hours depending on the buffer pool size and the amount of data. Once the buffer pool is populated, performance will be significantly better than before. This is why I advise against restarting during peak hours.
Q: Can I use this config for smaller VPS instances, like 8GB or 16GB RAM?
Absolutely, but with proportionally smaller values. The principle is the same — buffer pool at about 50-60% of total RAM. For an 8GB VPS, set innodb_buffer_pool_size = 4G. For a 16GB VPS, set innodb_buffer_pool_size = 8-10G. Other parameters like table_open_cache and tmp_table_size also need to be scaled down accordingly. The important thing is understanding the principles, not the exact numbers — adjust based on available resources.
Q: I applied this config but load is still high. What should I do next?
If load remains high after config optimization, the problem likely lies elsewhere. Check the slow query log for unindexed queries. Use EXPLAIN to analyze query plans. The issue might also be in the application creating too many connections or running inefficient queries. For further diagnosis, check our guide on Linux server monitoring or MySQL slow query troubleshooting.
Related Articles
- Optimizing MySQL for VPS with Limited RAM
- Complete Guide to Linux Server Monitoring
- LiteSpeed Cache Optimization for WordPress
- Fixing MySQL Slow Queries on Shared Hosting
- High WordPress Load — Causes & Complete Solutions
MySQL load issues can be frustrating, but with the right configuration, a server with 80 cores and 256GB of RAM should be able to handle thousands of websites without breaking a sweat. The key is tuning your configuration to match your actual hardware specs instead of relying on defaults. If you need help monitoring or optimizing your server infrastructure, don’t hesitate to reach out to our NOC team.