必须停库后手动配置innodb_temp_data_file_path,否则ibtmp1会无限增长占满磁盘;因其默认autoextend无上限,且仅在启动时生效,不重启则配置永不生效。

必须停库后手动配置 innodb_temp_data_file_path,否则 ibtmp1 会无限增长到占满磁盘——这不是配置没生效,是根本没机会生效。
为什么新装 MySQL 8.0 的 ibtmp1 一跑就涨到几 GB?
MySQL 8.0 默认启动时自动创建一个名为 ibtmp1 的共享临时表空间文件,初始约 12MB,但默认配置是 ibtmp1:12M:autoextend(无上限)。只要查询触发磁盘临时表(比如大 GROUP BY、窗口函数、JSON 解析),它就持续追加写入,且重启前绝不收缩。你看到的“刚装好就爆了”,大概率是首次执行报表类 SQL 就踩中了这个坑。
- 不是磁盘不够,是 ibtmp1 单文件在高并发下频繁扩展 + 元数据锁争用,导致 I/O 延迟飙升
- 监控
Created_tmp_disk_tables上升快,但/tmp目录却很空——说明数据全进了ibtmp1,而非传统 tmpdir - 错误提示如
The table '/tmp/#sql' is full是误导性路径名,实际落盘位置就是ibtmp1
怎么安全设置 innodb_temp_data_file_path?
该参数不能动态修改,必须写入配置文件并彻底重启。关键不是“设多大”,而是“怎么分”和“上限在哪”:
- 绝对不要只写
ibtmp1:12M:autoextend—— 缺少:max:2G就等于没设防 - 推荐显式配置多个等大小文件,例如:
ibtmp1:12M:autoextend:max:2G;ibtmp2:12M:autoextend:max:2G;ibtmp3:12M:autoextend:max:2G - 每个文件独立分配/清理,降低锁竞争;分号
;是必需分隔符,漏掉整个配置会被忽略 - 路径必须可写:MySQL 进程用户(如
mysql)需对datadir(通常是/var/lib/mysql或C:\phpEnv\MySQL\data)有写权限
别忘了配 temptable_max_ram 和 tmp_table_size
只调 innodb_temp_data_file_path 不够,MySQL 8.0.16+ 默认用 TempTable 引擎,它的内存限额由独立参数控制:
-
temptable_max_ram决定 TEMPTABLE 引擎最多用多少内存做“内存阶段”,超了直接写ibtmp1;默认是总内存 3%,64GB 机器才约 2GB,报表查询很容易突破 -
tmp_table_size和max_heap_table_size必须设为相同值(如256M),否则取小者生效,调一个等于白调 - 三者要协同:例如
temptable_max_ram = 4G+tmp_table_size = max_heap_table_size = 256M+innodb_temp_data_file_path = ...:max:10G
验证与清理旧 ibtmp1 的硬步骤
改完配置不等于生效。常见失效原因全是操作链断裂:
- 执行
SELECT @@innodb_temp_data_file_path;,输出必须和配置文件里一模一样(含大小写、分号、单位),否则说明服务没真正重启或配置写错段落 - 必须先执行
SET GLOBAL innodb_fast_shutdown = 0;,再SHUTDOWN;,确保旧ibtmp1可被安全删除 - 关闭后手动删掉
datadir下的ibtmp1(注意:不是ibdata1,也不是#innodb_temp目录下的.ibt文件) - Windows phpEnv 用户:必须右键托盘图标 → “Restart MySQL Service”,点控制面板里的“Restart MySQL”无效
最常被忽略的一点:即使所有参数都配对、重启干净、ibtmp1 重置回 12MB,只要业务里存在长事务未提交,或某个连接卡在 Creating tmp table 状态,ibtmp1 就无法释放——它不是文件系统级的“空闲”,而是 InnoDB 内部的“逻辑占用”。查活跃临时表用 SELECT * FROM information_schema.INNODB_TEMP_TABLE_INFO;,比看文件大小管用得多。











