MySQL

InnoDB Buffer Pool Tuning: Sizing, Hit Ratio, and Warm-Up Strategies

Size and tune the MySQL 8.4 InnoDB buffer pool from a complete memory budget, measured I/O and latency, safe resize tests, and restart warm-up behavior.

JusDB Team
Published August 4, 2025
Updated August 1, 2026
5 min read

The InnoDB buffer pool caches table and index pages and holds modified pages before they are flushed. A larger pool can reduce storage reads, but an oversized pool can force the operating system to reclaim memory or swap, causing worse latency than a smaller, stable configuration. There is no universal percentage that is correct for every MySQL host.

In short
  • Budget memory for MySQL's global allocations, peak connection and query workspaces, other processes, and the operating system before sizing the pool.
  • Measure changes in physical reads, request latency, dirty-page pressure, and host memory; a hit ratio has no universal pass mark.
  • Online resize is useful but can briefly block work and shrinking can force page eviction and I/O.
  • Buffer-pool dump/load can reduce cold-start impact, but it does not replace controlled restart testing.

Build a memory budget

Start with installed RAM, then reserve memory for the OS and filesystem, monitoring and backup agents, co-located services, MySQL's non-buffer-pool global allocations, and the peak—not average—memory used by concurrent sessions. Sorts, joins, temporary tables, connection buffers, Performance Schema, replication, and backup work can all add pressure. Keep enough headroom for unusual concurrency and maintenance.

On a host dedicated to MySQL, innodb_dedicated_server=ON can calculate selected InnoDB memory and log settings. For the buffer pool, MySQL 8.4 uses 128 MB on hosts with at most 1 GB detected memory, 50% between 1 GB and 4 GB, and 75% above 4 GB. Do not enable this automatic mode on a shared host; it assumes MySQL can use most server resources.

Inspect the active configuration

sql
SHOW GLOBAL VARIABLES WHERE Variable_name IN (
  'innodb_buffer_pool_size',
  'innodb_buffer_pool_instances',
  'innodb_buffer_pool_chunk_size',
  'innodb_buffer_pool_dump_at_shutdown',
  'innodb_buffer_pool_load_at_startup',
  'innodb_buffer_pool_dump_pct',
  'innodb_old_blocks_pct',
  'innodb_old_blocks_time'
);

For multiple buffer-pool instances, MySQL requires each instance to be at least 1 GB and supports up to 64 instances. Multiple instances can reduce contention on large pools, but “one instance per GB” is not an official sizing rule. Keep the default unless mutex evidence and repeatable load tests justify a change.

Measure cache misses as deltas

sql
SHOW GLOBAL STATUS WHERE Variable_name IN (
  'Innodb_buffer_pool_read_requests',
  'Innodb_buffer_pool_reads',
  'Innodb_buffer_pool_pages_data',
  'Innodb_buffer_pool_pages_dirty',
  'Innodb_buffer_pool_pages_free',
  'Innodb_buffer_pool_wait_free',
  'Innodb_data_reads',
  'Innodb_data_read'
);

Innodb_buffer_pool_read_requests counts logical requests and Innodb_buffer_pool_reads counts reads that could not be satisfied from the pool. A cache-hit estimate over an interval is 1 - delta(reads) / delta(read_requests). Use two samples around a representative workload because global counters are cumulative. A high ratio can coexist with a small set of latency-critical misses, and a lower ratio can be acceptable for scans or a working set larger than RAM.

Correlate the deltas with query latency, storage read latency and throughput, free/available host memory, swap activity, dirty-page percentage, flush pressure, and Innodb_buffer_pool_wait_free. Tune a bottleneck, not a standalone ratio.

Resize in controlled steps

innodb_buffer_pool_size is dynamic. The resulting size is aligned to the buffer-pool chunk size multiplied by the number of instances, so the effective value can differ from the request. The following is an illustrative 8 GiB target, not a general recommendation:

sql
SET GLOBAL innodb_buffer_pool_size = 8589934592;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_resize_status';

Use SET PERSIST only after the trial is accepted and the configuration ownership model permits MySQL's persisted-variables file. Otherwise update the managed configuration through the normal deployment system.

Online does not mean impact-free

Allocation and deallocation can briefly block operations in critical paths. Shrinking a pool can evict pages and increase reads or flushing. Change one step at a time during an observed window, monitor resize status and latency, and keep a rollback value that fits the memory budget.

Warm-up after restart

MySQL 8.4 enables innodb_buffer_pool_dump_at_shutdown and innodb_buffer_pool_load_at_startup by default. The dump stores page identifiers, not page contents; startup uses that list to read selected pages back into the pool. The default innodb_buffer_pool_dump_pct is 25, representing the most recently used portion of each pool.

sql
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_dump_status';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_load_status';

-- Controlled manual operations:
SET GLOBAL innodb_buffer_pool_dump_now = ON;
SET GLOBAL innodb_buffer_pool_load_now = ON;

Do not trigger a manual load during a latency-sensitive period without testing: it creates storage reads. Validate restart behavior with real readiness checks. A process that accepts TCP connections can still be cold for the workload.

Reduce scan pollution carefully

InnoDB divides the LRU into old and new sublists so a large scan does not immediately displace every hot page. innodb_old_blocks_pct controls the old sublist share. innodb_old_blocks_time is 1000 milliseconds by default, meaning a page must remain in the old sublist for that interval before another access can promote it. Setting it to 1000 is therefore not an increase on a default MySQL 8.4 server.

Change these settings only when workload evidence shows large scans displacing useful pages. Query plans and indexes are usually the first place to fix accidental scans. A deliberate analytical scan may be better isolated from an OLTP server.

A safe tuning loop

  1. Capture a peak-period baseline: latency distribution, throughput, physical-read deltas, dirty pages, storage behavior, available memory, and swap.
  2. Identify whether misses or flushing actually constrain the user-facing workload.
  3. Model memory under worst credible concurrency, including maintenance.
  4. Change one variable or pool-size step and observe a complete workload cycle.
  5. Persist only a repeatable improvement with safe memory headroom.
  6. Re-test restart warm-up, backup work, replication, and failover behavior.

Official primary sources

Working with JusDB on MySQL performance

JusDB helps teams build memory budgets, measure buffer-pool behavior, run controlled resize tests, and validate warm-up and failover performance under production-shaped load.

Explore JusDB MySQL services →  |  Talk to a DBA

Share this article

Database engineering notes

Articles like this one, in your inbox. No spam, unsubscribe anytime.

JusDB Team

Official JusDB content team

Keep reading

MySQL Explained (2026): InnoDB, 8.4 LTS, Replication & Production Patterns

Everything you need to know about MySQL: storage engines, replication topologies, performance tuning, and cloud deployment. From basics to advanced optimization.

MySQL9 minMay 13, 2026
Read

MySQL binlog Retention, Rotation & Purge: Production Guide (2026)

Configure MySQL binlog retention safely: binlog_expire_logs_seconds, manual purging rules, AWS RDS retention, and the disk-exhaustion failure mode you should monitor for.

MySQL10 minMay 9, 2026
Read

MySQL "Communications Link Failure": Fix wait_timeout, HikariCP & All 8 Timeout Variables

MySQL wait_timeout, net_read_timeout, innodb_lock_wait_timeout and max_execution_time — production tuning rules and the HikariCP alignment trick that prevents 'communications link failure' errors.

MySQL6 minMay 9, 2026
Read