触发器调用自定义函数报错的核心原因是mysql对函数的确定性声明和调用者权限链进行双重校验,缺一不可:error 1370因definer无execute权限,error 1418因未声明deterministic/no sql且log_bin_trust_function_creators=0。

触发器调用自定义函数时报错,核心原因不是函数本身写得不对,而是 MySQL 在执行时对函数的「确定性声明」和「调用者权限链」做了双重校验——缺一不可。
为什么 SHOW CREATE TRIGGER 看起来正常,但 INSERT 就报 ERROR 1370 或 ERROR 1418
因为触发器执行时走的是 DEFINER 上下文,而函数又有一层自己的 SQL SECURITY 设置。两者权限不匹配,就会在运行时崩掉:
-
ERROR 1370 (42000):当前DEFINER用户没被授予EXECUTE权限(注意是函数名,不是数据库名) -
ERROR 1418 (HY000):函数没声明DETERMINISTIC或NO SQL,且log_bin_trust_function_creators=0 - 即使函数能单独调用成功,被触发器调用时仍可能失败——因为触发器的
DEFINER≠ 函数的DEFINER
必须同时检查函数和触发器的 DEFINER 与 SQL SECURITY
运行这两条命令,逐项比对:
SHOW CREATE FUNCTION my_func;
SHOW CREATE TRIGGER my_trigger;
重点关注:
- 函数的
DEFINER是否存在?是否被锁?是否对函数内访问的表有 SELECT/INSERT 权限? - 函数是否带
SQL SECURITY DEFINER(默认值)?如果是,DEFINER必须有函数体里所有语句的权限 - 触发器的
DEFINER是否和函数的DEFINER是同一账号?如果不是,就得确保两个账号都拥有各自所需权限 - 若想绕开
DEFINER权限链,可把函数改为SQL SECURITY INVOKER,但调用者(即触发器的DEFINER)必须有函数内全部操作权限
GRANT EXECUTE 必须精确到函数名,不能省略关键字
给函数授执行权,语法非常严格:
- ❌
GRANT EXECUTE ON mydb.my_func TO 'u'@'%'—— 缺FUNCTION关键字,MySQL 当成数据库权限处理,静默失败 - ✅
GRANT EXECUTE ON FUNCTION mydb.my_func TO 'u'@'%'—— 唯一有效写法 - ⚠️
GRANT EXECUTE ON FUNCTION mydb.* TO 'u'@'%'—— 虽然能执行,但会授权该库下所有函数,含他人创建的,违反最小权限原则 - 别忘了验证:
SHOW GRANTS FOR 'u'@'%'输出里必须出现GRANT EXECUTE ON FUNCTION `mydb`.`my_func`
log_bin_trust_function_creators=1 不是万能解药,只是前置条件
只要开启了 binlog(log_bin=ON),调用含 NOW()、RAND()、子查询等非确定性逻辑的函数,就必须满足两个条件:
-
log_bin_trust_function_creators = 1(全局变量或配置文件中设置) - 函数定义中显式声明
DETERMINISTIC或NO SQL(哪怕逻辑确实是确定性的,也必须写) - 只设变量不加声明,或只加声明不设变量,都会触发
ERROR 1418 - 云数据库(如阿里云 RDS)通常禁用
SUPER,所以SET GLOBAL方式临时开启是唯一路径
真正容易被忽略的是:函数和触发器的 DEFINER 往往不同,而权限检查是分别进行的——你得挨个确认每个账号是否存在、未锁定、且对各自涉及的表有对应 DML 权限,而不是只修一个地方就以为万事大吉。











