还原前必须检查源库和目标库的sql_mode是否一致,否则可能导致insert失败(如no_zero_date拒绝'0000-00-00')或静默数据偏差;建议导出时手动插入set sql_mode语句固化源库模式,并排查配置文件加载路径、作用域及连接级覆盖。

还原前必须检查源库和目标库的 sql_mode 是否一致
MySQL逻辑还原(如 mysqldump 导出再导入)时,sql_mode 不一致会直接导致 SQL 执行失败或静默数据偏差——比如源库允许 '0000-00-00' 日期,目标库启用了 NO_ZERO_DATE,还原脚本就会卡在某条 INSERT 上。
实操建议:
- 还原前务必执行:
SELECT @@sql_mode;分别在源库和目标库运行,逐项比对输出值 - 特别注意是否含
STRICT_TRANS_TABLES、NO_ZERO_DATE、ONLY_FULL_GROUP_BY这三类高频冲突项 - 若使用 RDS 或托管服务,确认控制台参数页中
sql_mode设置是否被覆盖(部分云厂商默认锁定某些 mode)
mysqldump 导出时带上 --set-gtid-purged=OFF 和显式 sql_mode
默认 mysqldump 不保存 sql_mode,还原时完全依赖目标库当前设置。这不是 bug,是设计行为。
安全做法是导出时主动固化模式:
- 导出命令加参数:
mysqldump --set-gtid-purged=OFF --skip-triggers --no-tablespaces -u root -p db_name > dump.sql - 手动在
dump.sql开头插入一行:SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';(值取自源库SELECT @@sql_mode输出) - 避免用
--compatible=ansi等自动改写选项,它可能干扰字段默认值处理逻辑
还原中途报错 Field 'xxx' doesn't have a default value 怎么快速定位
这是 STRICT_TRANS_TABLES 启用后最常见报错,本质是目标库比源库更严格,而非 dump 文件有问题。
不要直接关 strict mode,先快速判断问题范围:
- 查报错行附近的
INSERT语句,看是否漏写了 NOT NULL 且无 DEFAULT 的字段 - 用
SHOW CREATE TABLE table_name;对比源库和目标库表结构,重点看DEFAULT和NULL属性是否一致 - 临时跳过单条语句调试:在目标库执行
SET SESSION sql_mode = '';,再 source dump.sql ——仅用于定位,不可用于生产还原 - 若表结构本身不一致(如目标库字段少一个),说明备份/迁移流程有遗漏,不是
sql_mode问题
配置文件里写了 sql_mode 却没生效?重点查这三处
my.cnf 中的 sql_mode 设置失效很常见,根本原因不是配置写错,而是加载时机和作用域混乱。
排查顺序:
- 确认修改的是正确的配置文件:用
mysql --help | grep "Default options"查找实际加载路径,常见位置包括/etc/my.cnf、/etc/mysql/my.cnf、/usr/etc/my.cnf - 确认配置在
[mysqld]段下,且没有被其他同名配置覆盖(如/etc/mysql/conf.d/下的文件可能后加载) - 重启后仍无效?执行
SELECT @@global.sql_mode;,如果返回空或旧值,说明 mysqld 启动时根本没读到该配置——检查文件权限(需 mysql 用户可读)、是否有语法错误(如引号不匹配)、是否被 systemd service 文件中的Environment=覆盖
真正容易被忽略的是:即使全局配置生效,应用连接时仍可能通过 init_connect 或 JDBC URL 参数(如 ?sessionVariables=sql_mode='')覆盖 session 级别的 mode。还原操作务必用 clean 连接,不要复用已有连接池。











