Skip to main content

Server Configuration Tuning

Learning Focus

Use this lesson to understand MySQL server configuration tuning — adjusting internal settings to maximize performance for your specific workload and hardware.

Concept Overview​

Why Tune MySQL Configuration?​

MySQL's default configuration is designed to work on modest hardware with minimal resource usage. Defaults are rarely optimal for production. Tuning the configuration can dramatically improve:

  • Query response time — more data cached in memory = fewer disk reads
  • Throughput — more concurrent connections handled efficiently
  • Stability — proper buffer sizes prevent out-of-memory errors and crashes

The Tuning Philosophy​

Measure first, tune second. Never change a setting without understanding what it does and measuring the impact.

Key Areas to Tune​

AreaPrimary SettingsImpact
InnoDB Buffer Poolinnodb_buffer_pool_sizeBiggest single performance factor
Connection Handlingmax_connections, thread_cache_sizeHandles concurrent users
Query Executiontmp_table_size, sort_buffer_sizeComplex query performance
Logginglog_bin, sync_binlogReplication and recovery
I/Oinnodb_io_capacity, innodb_flush_log_at_trx_commitDisk write performance

Basic Syntax & Rules​

Viewing Current Settings​

-- View a specific variable
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';

-- View all InnoDB variables
SHOW VARIABLES LIKE 'innodb%';

-- View status counters
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%';
SHOW GLOBAL STATUS LIKE 'Threads%';

Setting Variables​

-- Set for current session only
SET SESSION sort_buffer_size = 4 * 1024 * 1024; -- 4MB

-- Set globally (affects new connections)
SET GLOBAL max_connections = 200;

-- Some changes require restart (persistent in my.cnf)

Configuration File (my.cnf)​

[mysqld]
# InnoDB Buffer Pool (most important setting)
innodb_buffer_pool_size = 4G

# Connections
max_connections = 200
thread_cache_size = 16

# Temporary tables
tmp_table_size = 64M
max_heap_table_size = 64M

# I/O
innodb_io_capacity = 2000
innodb_io_capacity_max = 4000

# Logging
slow_query_log = ON
long_query_time = 1

Step-by-Step Examples​

Example 1: Tuning the InnoDB Buffer Pool​

The buffer pool is MySQL's most important performance setting. It caches table data and indexes in memory, avoiding disk reads.

Step 1: Check current size and hit rate

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- Default: 128M (far too small for production)

-- Check buffer pool hit rate
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';

Calculate hit rate:

SELECT
(1 - (
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads')
/
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests')
)) * 100 AS buffer_pool_hit_rate_pct;
buffer_pool_hit_rate_pct
98.50

Target: 99%+ hit rate. Below 95% means the buffer pool is too small.

Step 2: Set optimal size

Rule of thumb: Set innodb_buffer_pool_size to 50–75% of total server RAM (on a dedicated database server).

# Server with 8GB RAM:
[mysqld]
innodb_buffer_pool_size = 5G
innodb_buffer_pool_instances = 4 # divide into 4 instances for concurrency

Step 3: Apply and verify

-- Dynamic resize (MySQL 8.0+, no restart needed)
SET GLOBAL innodb_buffer_pool_size = 5368709120; -- 5GB in bytes

-- Verify
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';

Example 2: Tuning Connection Settings​

Step 1: Check connection usage

SHOW GLOBAL STATUS LIKE 'Max_used_connections';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_cached';
SHOW VARIABLES LIKE 'max_connections';
VariableValue
Max_used_connections85
max_connections151 (default)

Step 2: Set appropriate limits

[mysqld]
# Set to peak usage + 20% buffer
max_connections = 150

# Cache threads to avoid thread creation overhead
thread_cache_size = 16

# Timeout idle connections
wait_timeout = 300
interactive_timeout = 300

Don't blindly increase max_connections! Each connection uses ~10MB of memory. 1000 connections = 10GB just for connection overhead.


Example 3: Tuning Temporary Table Settings​

When MySQL creates temporary tables for sorting or grouping, they start in memory. If they exceed the size limit, they spill to disk (much slower).

-- Check how many temp tables went to disk
SHOW GLOBAL STATUS LIKE 'Created_tmp_tables';
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';
VariableValue
Created_tmp_tables50000
Created_tmp_disk_tables5000

If more than 10% of temp tables go to disk, increase the limits:

[mysqld]
tmp_table_size = 64M
max_heap_table_size = 64M # Both must be set — MySQL uses the smaller value

Example 4: InnoDB Flush Settings (Durability vs. Speed)​

[mysqld]
# Full ACID durability (default, safest)
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1

# Better performance, slight durability risk (1-second data loss window)
innodb_flush_log_at_trx_commit = 2
sync_binlog = 0
ValueBehaviorWhen to Use
= 1Flush to disk on every commitFinancial systems, any data where loss is unacceptable
= 2Flush to OS cache on commit, disk sync every secondMost applications — good performance with minimal risk
= 0Flush every second regardless of commitsBatch imports, dev environments

Practical Use Cases​

1. Dedicated Database Server (8GB RAM)​

[mysqld]
innodb_buffer_pool_size = 5G
innodb_buffer_pool_instances = 4
max_connections = 200
thread_cache_size = 16
tmp_table_size = 64M
max_heap_table_size = 64M
innodb_io_capacity = 2000
innodb_flush_log_at_trx_commit = 2
slow_query_log = ON
long_query_time = 1

2. Shared Server (2GB RAM)​

[mysqld]
innodb_buffer_pool_size = 512M
max_connections = 50
thread_cache_size = 8
tmp_table_size = 32M
max_heap_table_size = 32M

3. Development Environment​

[mysqld]
innodb_buffer_pool_size = 256M
max_connections = 20
innodb_flush_log_at_trx_commit = 2
slow_query_log = ON
long_query_time = 0.5

Common Mistakes & Troubleshooting​

MistakeWhat HappensHow to Fix
Leaving buffer pool at 128M defaultMost queries hit diskSet to 50-75% of RAM
Setting max_connections = 10000Server runs out of memorySet based on actual peak + 20%
Not setting max_heap_table_size with tmp_table_sizeMySQL uses the smaller of the twoAlways set both to the same value
Changing settings without measuring before/afterNo way to verify improvementRecord metrics before and after changes
Tuning too many variables at onceCan't identify which change helpedChange one variable at a time and measure
Ignoring slow query logPerformance problems go unnoticedAlways enable in production

Best Practices​

  • Start with the buffer pool — it has the biggest impact; tune it first
  • Measure before and after — use SHOW GLOBAL STATUS to verify improvements
  • Change one setting at a time — isolate the impact of each change
  • Use my.cnf for persistent changes — don't rely on SET GLOBAL alone
  • Monitor continuously — set up dashboards for key metrics
  • Don't over-allocate memory — leave room for the OS and other processes
  • Enable slow query log in production — catch regressions early
  • Review quarterly — as data and traffic grow, settings need adjustment

Hands-On Practice​

Exercise 1: Buffer Pool Analysis (Easy)​

Calculate your buffer pool hit rate. Is it above 99%? If not, what would be the ideal buffer pool size?

Exercise 2: Connection Analysis (Medium)​

  1. Check your current max_connections and Max_used_connections
  2. Is the setting appropriate?
  3. Check Threads_cached — is thread caching working?
  4. Adjust settings and verify

Exercise 3: Full Server Audit (Advanced)​

Write a comprehensive diagnostic query that reports:

  1. Buffer pool size and hit rate
  2. Max connections vs peak usage
  3. Temp tables disk ratio
  4. Current InnoDB flush setting
  5. Slow query log status

Generate a "tuning recommendations" report based on the findings.


Connection to Other Concepts​

Related ConceptHow It Connects
Query ProfilingProfiling reveals what's slow; config tuning provides the resources
IndexesEven the best configuration can't fix a missing index
Transactionsinnodb_flush_log_at_trx_commit directly affects transaction durability
Backup and Recoverylog_bin and sync_binlog affect backup capabilities
Event SchedulerMaintenance events run better with properly tuned resources

What to Learn Next​


Visual Learning Diagram​

flowchart TD
A["Query arrives"] --> B{"Data in\nbuffer pool?"}
B -->|Yes| C["⚡ Memory read\n(microseconds)"]
B -->|No| D["💾 Disk read\n(milliseconds)"]
D --> E["Load into buffer pool"]
E --> C

F["Buffer Pool Size\n(innodb_buffer_pool_size)"]
F -->|Larger| G["More data fits in memory\n→ Higher hit rate\n→ Faster queries"]
F -->|Smaller| H["Frequent disk reads\n→ Lower hit rate\n→ Slower queries"]

classDef fast fill:#28a745,stroke:#fff,color:#fff
classDef slow fill:#dc3545,stroke:#fff,color:#fff
class C,G fast
class D,H slow

Quick Reference​

-- Key diagnostic queries
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';

-- Key settings to tune (my.cnf)
-- innodb_buffer_pool_size = 50-75% of RAM
-- max_connections = peak + 20%
-- tmp_table_size = max_heap_table_size = 64M
-- thread_cache_size = 16
-- slow_query_log = ON
-- long_query_time = 1

-- Dynamic changes (no restart)
SET GLOBAL innodb_buffer_pool_size = 4294967296; -- 4GB
SET GLOBAL max_connections = 200;
SET GLOBAL slow_query_log = ON;

What's Next​