ERROR 1840 是 GTID 状态冲突而非数据损坏:导入 SQL 中的 SET @@GLOBAL.GTID_PURGED 与非空的 @@GLOBAL.GTID_EXECUTED 冲突;reset master 可清空 GTID 状态并删除 binlog,使导入成功,但生产环境慎用。

直接说结论:ERROR 1840 不是数据损坏,而是 GTID 状态冲突 —— 导入的 SQL 文件里有 SET @@GLOBAL.GTID_PURGED,但当前实例的 @@GLOBAL.GTID_EXECUTED 不为空,MySQL 拒绝覆盖。
为什么执行 reset master 能解决?
该命令会清空 @@GLOBAL.GTID_EXECUTED 和 @@GLOBAL.GTID_PURGED,同时删除所有二进制日志。它本质是“重置复制起点”,让实例回到 GTID 初始状态,从而允许导入脚本里的 SET @@GLOBAL.GTID_PURGED 执行成功。
注意:reset master 在生产环境慎用 —— 它会让从库无法继续同步(如果当前是主库),且丢失所有 binlog 历史。仅适用于单机开发/测试库、新装库、或确认无主从依赖的场景。
- 执行前务必确认:当前 MySQL 实例未被任何从库连接,也未开启
log_slave_updates - 执行后
SHOW MASTER STATUS的File和Position全部归零,Executed_Gtid_Set变为空 - 命令本身不重启 mysqld,但需在 MySQL 客户端内执行:
mysql> reset master;
删掉 SQL 文件里的 SET @@GLOBAL.GTID_PURGED 行更安全
如果你只是想还原数据、不关心 GTID 一致性(比如本地开发、CMS 重装、单库迁移),直接编辑 SQL 文件最稳妥 —— 这避免了任何 GTID 状态操作。
打开导出的 SQL 文件,搜索这两行(通常在文件头部):
SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN; SET @@GLOBAL.GTID_PURGED=...;
把整行 SET @@GLOBAL.GTID_PURGED=... 删除(包括结尾分号),保存后重新导入即可。
- 注意:有些导出文件可能含多条
GTID_PURGED设置(如分库导出合并),要全部删掉 - 不要只注释(比如加
--),MySQL 解析时仍会报语法错误 - 若用
vim处理大文件,可用命令快速删除::g/SET @@GLOBAL.GTID_PURGED/d
mysqldump 导出时就禁用 GTID 记录
下次再导出,加 --set-gtid-purged=OFF 参数,一劳永逸避开这个问题。
标准写法示例:
mysqldump -u root -p --set-gtid-purged=OFF --databases myapp > myapp.sql
这个参数的作用是:跳过写入 SET @@GLOBAL.GTID_PURGED 语句,也不设置 SQL_LOG_BIN=0,完全不干扰目标库的 GTID 状态。
- 它不影响数据正确性,只影响 GTID 元信息 —— 对单库还原、开发环境、无主从场景完全够用
- 若导出的是全库(
--all-databases),必须加此参数,否则默认为AUTO,容易触发 1840 - MySQL 5.7.6+ 支持;低于此版本该参数不存在,需手动删或用
reset master
真正容易被忽略的点是:同一个 SQL 文件,在 A 库能导入、B 库报 1840,往往不是文件问题,而是 B 库之前执行过事务(哪怕只是建了个表),导致 GTID_EXECUTED 非空 —— 所以判断是否要 reset master,先看 SELECT @@GLOBAL.GTID_EXECUTED; 返回是不是空值。


















