MySQL主从架构下触发器默认只在主库执行,从库不执行是设计使然而非故障;主库仅同步binlog事件,不复制触发器逻辑,ROW模式下从库重放行变更而不触发任何触发器,强行启用将导致重复写入、主从不一致及复制中断等严重问题。

主从架构下触发器默认只在主库生效,不是配置遗漏或 bug,而是 MySQL 复制机制的必然结果——从库不执行触发器是设计使然,不是故障。
主库写 binlog,从库只重放语句或行变更
MySQL 主从复制靠 binlog 传输变更,但触发器逻辑本身不进 binlog。比如主库 AFTER INSERT ON orders 往 orders_log 插日志,这个 INSERT INTO orders_log 不会被记录到 binlog 中;从库收到的只是原始的 INSERT INTO orders,重放时不会“再触发一次”。所以即使你在从库上也建了同名触发器,它也不会被调用(除非 binlog_format = STATEMENT 且满足一堆危险前提)。
从库强行启用触发器要同时踩三个坑
-
binlog_format必须设为STATEMENT:但该模式已基本弃用,NOW()、UUID()、自增主键等会导致主从不一致 - 从库必须关闭
read_only = ON:否则触发器内任何写操作(如INSERT INTO audit_log)直接报错ERROR 1290 (HY000) - 触发器
DEFINER用户必须在从库存在且有TRIGGER权限:否则SHOW TRIGGERS能看见,实际加载失败,静默跳过
ROW 模式下“从库触发”等于埋雷
现在生产环境几乎全用 binlog_format = ROW,这是安全底线。此时若硬要在从库跑触发器:
- 主库触发一次、从库又触发一次 → 日志表重复写入,
orders_log行数翻倍 - 触发器里含
SELECT ... FOR UPDATE或跨表更新 → 极易和主库同步流抢锁,引发复制延迟甚至中断 - 某次从库触发失败(如目标表不存在、磁盘满),整个 SQL 重放卡住,
Seconds_Behind_Master持续上涨
替代方案比“让从库触发”更可控
真需要从库侧响应变更,别碰触发器:
- 应用层双写:主库写
orders后,同步写orders_log—— 逻辑清晰、可重试、可观测 - 监听 binlog:用
Canal或Maxwell解析orders变更,投递到下游服务处理审计/同步逻辑 - 物化视图或汇总表:用定时任务或 Flink CDC 做最终一致性聚合,不强求实时
最常被忽略的一点:触发器一旦跨主从边界,就脱离事务边界。主库事务成功 ≠ 从库触发动作成功,而你很难给它加回滚或补偿——这点在金融、订单类场景里尤其致命。


















