mysql主从复制中ddl语句默认同步,但存在同步失败或错乱风险,关键取决于binlog_format、read_only设置、崩溃恢复及执行时序;安全执行需用pt-online-schema-change等工具或停sql线程手动操作,并校验结构一致性。

DDL 语句在 MySQL 主从复制中默认是同步的
MySQL 主从复制默认基于 binlog,而 CREATE、ALTER、DROP 等 DDL 语句只要成功执行,就会被写入 binlog(格式为 STATEMENT 或 ROW),从库 IO 线程拉取后,SQL 线程会重放——所以结构变更天然会被同步,无需额外开启开关。
但“能同步”不等于“一定安全同步”,实际中常见问题不是“不同步”,而是“同步失败”或“同步错乱”。关键取决于以下几点:
-
binlog_format必须不是NONE;推荐用ROW或MIXED,避免STATEMENT下某些 DDL(如含UUID()、NOW())产生主从不一致 - 从库不能处于
read_only=ON且未显式授权SUPER权限给复制用户(否则ALTER TABLE等操作会被拒绝) - DDL 执行期间若主库发生 crash,而 binlog 尚未刷盘,该 DDL 可能丢失,导致主从结构不一致
为什么从库报错 “Table doesn’t exist” 却明明主库刚建完
这不是同步没发生,而是同步延迟或执行顺序问题。典型场景:
- 主库执行
CREATE TABLE t1后立刻执行INSERT INTO t1,而从库 SQL 线程还没来得及建表就收到 INSERT —— 在STATEMENT模式下会直接报错;ROW模式下虽不会报这个错,但若 DDL 和 DML 被分到不同 binlog event 组,仍可能因并发回放逻辑(如slave_parallel_workers > 0)导致时序错乱 - 从库开启了
slave_ddl_exec_mode=IDEMPOTENT(MySQL 8.0.27+),但主库没有,导致从库对重复 DDL 做了忽略,掩盖了上游本应失败的操作 - 应用层误在从库手动建了同名表,后续主库 DDL 到达时触发冲突(如
CREATE TABLE IF NOT EXISTS不报错,但ALTER TABLE会失败)
如何安全执行线上 DDL 并确保主从结构一致
核心原则:把 DDL 当作“可能阻塞、可能失败、需要验证”的高危操作,而不是“执行完就完事”。实操建议:
- 优先使用
pt-online-schema-change或gh-ost工具,它们通过影子表 + 触发器/二进制日志解析实现无锁变更,并自动校验主从表结构和数据一致性 - 若必须原生命令,先在从库停掉 SQL 线程:
STOP SLAVE SQL_THREAD,再在主库执行 DDL,确认SHOW MASTER STATUS记录位置后,手动在从库执行相同 DDL,再START SLAVE - 执行后立即检查:
SHOW SLAVE STATUS\G中Seconds_Behind_Master是否归零、Exec_Master_Log_Pos是否推进、Slave_SQL_Running_State是否为 "Slave has read all relay log" - 用
mysqldiff(MySQL Utilities)或pt-table-checksum对比主从库表结构:mysqldiff --server1=user:pass@host1 --server2=user:pass@host2 db1.table1:db2.table1
MySQL 8.0 的原子 DDL 对主从同步的影响
MySQL 8.0 引入原子 DDL 日志(mysql.innodb_ddl_log),让单个 DDL 内部操作(如删元数据 + 删文件)具备事务性。这对主从的意义是:
- 主库上 DDL 要么全部成功,要么全部回滚,不会出现“建了表但没写 frm 文件”这类半成品状态,降低了从库同步出错概率
- 但原子性只作用于单实例,**不改变 binlog 写入行为**:DDL 仍以完整语句形式写入 binlog,从库仍是“重放语句”,不是“复现原子过程”
- 注意:
innodb_ddl_log表本身不复制,所以从库无法利用它做恢复;它只是主库崩溃恢复时的内部保障机制
真正影响同步可靠性的,还是 binlog 格式、复制过滤规则、以及是否跳过错误(如 SET GLOBAL sql_slave_skip_counter = 1)——这些比 DDL 原子性更常成为故障根源。










