MySQL报ERROR 1290或事务卡在COMMIT,八成是磁盘满触发自动只读保护;须先执行df -h和df -i确认空间与inode使用率,再查read_only和super_read_only状态,腾空磁盘后才可安全关闭只读开关。

MySQL报ERROR 1290或事务卡在COMMIT,八成是磁盘满了触发了只读保护,不是权限配置错了——先查df -h,再查read_only和super_read_only,顺序不能反。
为什么磁盘满会导致只读?
MySQL在磁盘使用率 ≥95% 时会自动把read_only设为ON,错误提示和你手动设置一模一样,但my.cnf里什么都没改。这不是bug,是保护机制:防止写入失败导致数据不一致或崩溃。InnoDB在COMMIT阶段要刷redo、写undo、更新doublewrite buffer,任一环节因ENOSPC失败,整个事务就回滚,日志里常显示ERROR 1030 (HY000): Got error 28 from storage engine。
容易踩的坑:
- 只看
df -h发现还有5%空间,却忽略df -i显示inode已100%,尤其binlog文件极多时 - 误以为
read_only = ON是人为配置,反复改配置文件或执行SET GLOBAL read_only = OFF,但磁盘没腾空间,改完立刻又变ON - 用
lsof +L1查到“幽灵文件”(已删但mysqld还占着句柄),却没及时kill -USR1或重启mysqld释放
怎么快速定位是不是磁盘满?
别进MySQL,先跑系统命令:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 执行
df -h和df -i,重点盯/var/lib/mysql所在分区(用SHOW VARIABLES LIKE 'datadir';确认) - 如果
df -h显示100%或≥95%,立刻查大头:du -sh /var/lib/mysql/* | sort -hr | head -5 - 如果
du总和远小于df显示已用空间,跑lsof +L1找被删除但仍被mysqld占用的文件 - 检查错误日志里有没有
No space left on device、OS error code 28或Can't create/write to file
确认只读开关状态并临时恢复写能力
进MySQL后只查两行:
-
SELECT @@GLOBAL.read_only, @@GLOBAL.super_read_only;—— 如果任一返回1,且磁盘确实满了,那就坐实了是自动触发 - 不要先执行
SET GLOBAL read_only = OFF:它会被磁盘监控逻辑再次拉回ON - 必须先腾出空间(清binlog、关慢日志、删临时文件),再执行
SET GLOBAL super_read_only = OFF;,最后SET GLOBAL read_only = OFF; - 注意:
super_read_only = ON时,连root都不可写;且这两个变量只对新连接生效,应用需重连或重启连接池
腾空间的实操优先级
按见效快慢排序,避免无效操作:
- 立刻停掉膨胀最快的日志:
SET GLOBAL slow_query_log = 'OFF';、SET GLOBAL general_log = 'OFF'; - 清理binlog:
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);(先SHOW SLAVE STATUS\G确认从库已同步) - 删临时大文件:
ls -lh /var/lib/mysql/ | grep -E '^.*#sql-|^ibtmp1$',后者可直接删(重启mysqld会重建) - 别急着
OPTIMIZE TABLE:碎片表腾空间慢,且需要额外空间生成临时文件,磁盘只剩几百MB时反而可能失败
最易被忽略的一点:云RDS(如阿里云、腾讯云)可能屏蔽super_read_only变量,或把“只读实例”开关映射为不可通过SQL修改的状态——这时必须进控制台关闭,而不是在MySQL里折腾SET GLOBAL。

















