MySQL被OOM Killer杀掉时,需限制其总内存上限而非仅调优配置;重点管控innodb_buffer_pool_size(建议≤物理内存70%~80%且预留≥2GB)、max_connections及per-connection缓冲参数,并确认配置文件加载正确。

MySQL 内存溢出时,mysqld 进程被 OOM Killer 杀掉怎么办
直接看 /var/log/messages 或 dmesg 输出,如果出现类似 Out of memory: Kill process 1234 (mysqld) score 876,说明不是 MySQL 自己报错,而是系统级内存不足触发了 OOM Killer。这时候调 MySQL 配置没用,得先保命——限制 MySQL 总内存上限,不让它吃光系统资源。
- 确认系统总内存和 MySQL 实际使用量:
free -h和ps aux --sort=-%mem | head -5 - 临时降低 MySQL 内存压力:连上 MySQL 后执行
SET GLOBAL innodb_buffer_pool_size = 512*1024*1024;(例如设为 512MB),但注意该值必须是innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances的整数倍,否则会自动向下取整到合法值 - 真正生效要改配置文件:
/etc/my.cnf或/etc/mysql/my.cnf中的[mysqld]段,加一行innodb_buffer_pool_size = 1G(别写成1024M,MySQL 5.7+ 才支持 M/G 单位) - 别只盯
innodb_buffer_pool_size:它常占总内存 70% 以上,但sort_buffer_size、join_buffer_size、tmp_table_size、max_connections乘起来也吓人——比如max_connections=500且每个连接开 4MB 排序缓存,光这一项就可能吃掉 2GB
innodb_buffer_pool_size 设多大才安全
它不是越大越好。设太高会导致系统 swap 频繁,甚至触发 OOM;设太低则磁盘 IO 暴增,查询变慢。关键看“活跃数据集大小”,不是总数据量。
- 查当前缓冲池命中率:
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';,算(1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests),低于 95% 就该考虑加大 - 保守起见,Linux 上建议不超过物理内存的 70%~80%,且预留至少 2GB 给系统和其他进程(如 PHP-FPM、Redis)
- MySQL 5.7+ 支持在线调整(需满足条件):
SET GLOBAL innodb_buffer_pool_size = 2*1024*1024*1024;,但要求innodb_buffer_pool_instances≥ 1,且新值必须是 chunk_size 的整数倍(默认 chunk_size=128MB) - 如果用的是小内存机器(≤ 2GB),别硬塞 1.5G 给 buffer pool——
key_buffer_size(MyISAM)和query_cache_size(已弃用)残留配置也可能抢内存,顺手清掉
为什么改了 my.cnf 重启后内存还是飙高
配置项没生效,或生效了但被其他参数间接放大。最常见是 max_connections 和 per-connection 缓冲区叠加爆炸。
- 检查是否真加载了你的配置文件:
mysqld --verbose --help | grep "Default options",确认路径对;再用mysql -e "SELECT @@basedir, @@datadir, @@config_file;"(5.7+)辅助验证 - 重点排查这些易忽略的 per-connection 参数:
sort_buffer_size(默认 256KB)、read_buffer_size(128KB)、join_buffer_size(256KB)——它们在每个连接建立时分配,不共享 - 如果应用用了连接池(如 HikariCP),实际并发连接数可能远高于你预期;用
SHOW STATUS LIKE 'Threads_connected';看实时连接数,再结合SHOW VARIABLES LIKE '%buffer%';估算理论峰值内存 - 某些云数据库(如阿里云 RDS)会屏蔽部分变量,
SET GLOBAL可能被拒绝,此时只能提工单或换实例规格
OOM 后恢复服务,哪些配置项优先检查
别一上来就调大 buffer pool。先堵住漏点,防止反复崩溃。
- 立刻检查并降低:
max_connections(从 1000 改成 200)、tmp_table_size和max_heap_table_size(都设成 64M 起步),这两个控制内存临时表上限,大 GROUP BY 容易爆 - 禁用已废弃功能节省内存:
query_cache_type = 0(MySQL 8.0 已移除,5.7 建议关)、performance_schema = OFF(调试期可关,生产环境建议留 ON 但调低performance_schema_max_table_instances) - 确认没有大事务长期持有 buffer pool 页面:
SELECT * FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED LIMIT 5;,长时间运行的事务会让 buffer pool 无法淘汰旧页 - 如果用的是 MySQL 8.0+,注意
innodb_dedicated_server = ON会自动根据内存设 buffer pool,但它假设你是独占服务器——容器或混部环境务必关掉,手动配
内存问题从来不是单个参数的事。buffer pool 是主因,但 per-connection 缓冲、连接数、临时表、甚至 slow log 的日志缓冲区都会叠加。最容易被忽略的是:你以为改了配置就完事,其实没确认 MySQL 加载的是哪个配置文件,也没算过 max_connections × sort_buffer_size 的理论峰值。


















