MySQL 5.7升级8.0后内存飙升主因是innodb_buffer_pool_size默认行为突变(自动按物理内存推算并向上对齐)叠加performance_schema全开预占300–500MB,非bug而是配置逻辑升级;需显式固定chunk_size、调整instances确保整除,并关闭非必要P_S consumer。

MySQL 5.7 升级到 8.0 后内存占用飙升,90%以上是 innodb_buffer_pool_size 默认行为突变 + performance_schema 全开导致的,不是 bug,也不是“新版本更吃资源”,而是旧配置没跟上新逻辑。
innodb_buffer_pool_size 显示值和实际 RSS 差一大截
你看到 SHOW VARIABLES LIKE 'innodb_buffer_pool_size' 返回 40GB,但 ps aux 里 mysqld 的 RSS 达到 72GB——这通常是因为 InnoDB 实际分配量被向上对齐了。
- MySQL 8.0.22+ 会自动推导
innodb_buffer_pool_chunk_size(比如 64GB 机器算出 256MB),再乘以innodb_buffer_pool_instances(默认 8),最终分配 = chunk × instances × chunk 数量 - 而你配置的
innodb_buffer_pool_size只是“目标值”,InnoDB 必须满足:总大小能被chunk_size × instances整除;不满足就悄悄向上补齐 - 启动日志里如果出现
Buffer pool size rounded up to ...,就是这个原因 - 验证方法:
SELECT @@innodb_buffer_pool_chunk_size, @@innodb_buffer_pool_instances, @@innodb_buffer_pool_size;,手动算是否整除
解决办法:在 /etc/my.cnf 的 [mysqld] 段显式写死:innodb_buffer_pool_chunk_size = 128M(必须是 1M 整数倍),再设 innodb_buffer_pool_instances 为能整除总大小的值(如 buffer_pool_size=2G,instances 设 2、4 或 8)。
performance_schema 一开就多占 300–500MB
这不是错觉。MySQL 8.0 默认全量启用所有 instruments 和 consumers,其中 events_statements_history_long 和 events_transactions_history_long 这类长历史表,单个默认预分配 128MB+ 内存,且启动即占——查不查都吃。
- 确认真实占用:
SELECT * FROM performance_schema.memory_summary_global_by_event_name WHERE event_name LIKE 'memory/performance_schema/%' ORDER BY SUM_ALLOCATED DESC LIMIT 10; - 关掉非必要 consumer:
UPDATE performance_schema.setup_consumers SET ENABLED = 'NO' WHERE NAME IN ('events_statements_history_long', 'events_transactions_history_long'); - 限制大小(写入 my.cnf):
performance_schema_events_statements_history_long_size = 10000(默认 20000) - 注意配置文件路径:宝塔用户常改
/www/server/mysql/my.cnf,但 MySQL 默认只读/etc/my.cnf;用ps aux | grep mysqld | grep -- '--defaults-file'确认实际加载路径
buffer pool 预热机制导致启动后 RSS 陡增
MySQL 8.0 默认开启 innodb_buffer_pool_dump_at_shutdown 和 innodb_buffer_pool_load_at_startup,重启时会快速加载上次 dump 的热页(ib_buffer_pool 文件),表现为启动后几秒内 RSS 暴涨。
- 这不是泄漏,是预热行为,但容易误判为异常
- 检查状态:
SHOW VARIABLES LIKE 'innodb_buffer_pool_dump_at_shutdown';和SHOW VARIABLES LIKE 'innodb_buffer_pool_load_at_startup'; - 若实例重启频繁、或热数据集远小于 buffer pool 总量,建议关掉:
SET GLOBAL innodb_buffer_pool_load_at_startup = OFF;,并写入配置文件 - 还可调小 dump 范围:
innodb_buffer_pool_dump_pct = 10(默认 25,只 dump 最热 10% 页)
升级后配置没生效的隐藏坑
很多 DBA 改了配置却没效果,核心原因是 8.0 引入了 PERSIST 机制:SET PERSIST 写入的变量会存进 mysqld-auto.cnf,且**优先级高于 my.cnf**。
- 查当前生效源:
SELECT VARIABLE_NAME, VARIABLE_SOURCE, VARIABLE_PATH FROM performance_schema.variables_info WHERE VARIABLE_SOURCE IN ('PERSISTED', 'CONFIG'); - 查持久化变量:
SELECT * FROM performance_schema.persisted_variables; - 若发现
VARIABLE_SOURCE = 'PERSISTED'但你不记得设过,很可能是升级前遗留;可临时清空:RESET PERSIST;(慎用,会清除所有持久化设置) - 特别注意:
sort_buffer_size、read_rnd_buffer_size等 per-connection 参数,8.0 排序策略已变,同样值更容易触发磁盘 filesort,盲目调大反而加剧内存压力
真正容易被忽略的点是:MySQL 8.0 的“默认值”不是静态快照,而是动态适配结果。比如 innodb_buffer_pool_size 会按物理内存自动推算,innodb_buffer_pool_chunk_size 会按总内存动态选值——你没显式写死,它就自己算,而且算完还可能悄悄对齐扩容。


















