跨库触发器需显式授予目标库表的dml权限及函数execute权限,trigger权限仅支持库级授予,mysql 8.0+需启用binlog且推荐binlog_format=mixed/row,definer默认以定义者身份执行,建议设sql security invoker。

跨库触发器必须显式授予目标库表的DML权限
触发器里出现 INSERT INTO sys.audit_log 或 UPDATE otherdb.stats,MySQL 不会自动复用当前用户的源库权限。哪怕你已对 sys 库有 SELECT 权限,INSERT 仍需单独授权。
实操建议:
- 先用
SHOW CREATE TRIGGER trigger_name查出所有跨库操作语句 - 逐条提取目标库名、表名和操作类型(
SELECT/INSERT/UPDATE/DELETE) - 对每个目标对象执行对应授权,例如:
GRANT INSERT ON sys.audit_log TO 'dev'@'%' - 若跨库调用了自定义函数(如
myutils.gen_id()),还得补上:GRANT EXECUTE ON FUNCTION myutils.gen_id TO 'dev'@'%'
TRIGGER权限只能按库授予,无法收缩到表级
GRANT TRIGGER ON mydb.orders TO 'u'@'%' 是语法错误,MySQL 会报 ERROR 1064。TRIGGER 是数据库粒度权限,设计初衷就是防绕过——避免用户通过一张“白名单表”的触发器偷偷读写另一张“黑名单表”。
这意味着:
- 即使只打算在
orders表建触发器,也得授GRANT TRIGGER ON mydb.* TO 'u'@'%' - 生产环境应隔离用途库,比如专设
triggers_db,把所有触发逻辑相关对象(含被跨库写的表)集中放进去 - 绝不能授
GRANT TRIGGER ON *.*,尤其在多租户实例中,这等于开放全库触发器创建权
MySQL 8.0+ 不再需要 SUPER,但需确认版本和 binlog 配置
旧版 MySQL(5.7 及以前)建触发器必须 SUPER 权限,而 8.0+ 已废弃 SUPER,改用 TRIGGER 库级权限。但两个隐性条件常被忽略:
- 必须启用二进制日志(
log_bin=ON),否则CREATE TRIGGER会失败并提示ERROR 1227 - 若触发器内含非确定性函数(如
NOW()、UUID()),且binlog_format=STATEMENT,可能因主从不一致被拒绝;建议设为MIXED或ROW - 检查方式:
SELECT @@log_bin, @@binlog_format;
DEFINER 和 SQL SECURITY 决定权限检查上下文
触发器默认以 DEFINER 身份执行,不是调用者。如果 DEFINER='root'@'localhost',而当前用户没被授 INSERT 权限,MySQL 仍报 EXECUTE command denied,而非更具体的权限错误。
安全做法是显式设为 SQL SECURITY INVOKER:
- 重建触发器时加上:
CREATE DEFINER='dev'@'%' SQL SECURITY INVOKER TRIGGER ... - 这样权限检查就基于调用者,便于审计和最小权限分配
- 注意:修改
DEFINER需要SET USER权限,普通用户无法自行操作,必须由管理员执行
跨库触发器最易被忽略的是权限链断裂——你以为给了 TRIGGER 就万事大吉,其实触发器体里每一条 SQL 都在独立校验权限。连 SELECT 都可能卡住,更别说写入系统库或调用函数。务必逐行扫 SHOW CREATE TRIGGER 输出,别信“应该有权限”这种假设。











