MySQL默认SQL SECURITY为DEFINER,函数以创建者权限执行,易因用户删除、权限变更或跨环境部署导致ERROR 1418/1370;显式声明INVOKER可遵循最小权限原则并提升可移植性与可审计性。

MySQL 创建函数时并不强制要求显式指定 SQL SECURITY 属性——它有默认值,但不写会埋下权限和迁移隐患。
MySQL 默认用 SQL SECURITY DEFINER,但你得知道它在干什么
如果你创建函数时完全没写 SQL SECURITY,MySQL 会自动按 DEFINER 模式执行。这意味着:函数运行时检查的是 DEFINER 用户(通常是创建者)的权限,而不是调用者的权限。这看似省事,实则容易出问题:
- 当
DEFINER用户被删或权限变更,函数立刻报ERROR 1418或ERROR 1370,调用方完全不知情 - 函数里读了系统变量(比如
@@version),MySQL 8.0+ 还要求该DEFINER有SYSTEM_VARIABLES_ADMIN权限,否则直接失败 - 用 Flamerobin 等工具导出再导入时,可能因工具 bug 错误补上
SQL SECURITY DEFINER(实际本不该有),导致行为突变
不写 SQL SECURITY 的真实代价是隐性依赖
很多人以为“不写=不管”,其实等于把安全上下文绑定到当前用户身份和权限状态上,而这个状态极易漂移:
-
CREATE FUNCTION f() RETURNS INT RETURN 1;→ 自动变成DEFINER=CURRENT_USER+SQL SECURITY DEFINER - 如果该用户后续被
DROP USER,函数就变成“孤儿对象”,SHOW CREATE FUNCTION仍显示原DEFINER,但已无法验证权限 - 跨环境部署时,目标库未必存在同名
DEFINER,或权限配置不同,函数一调就崩
什么时候必须显式写 SQL SECURITY?
不是语法强制,而是工程必需:
- 你想让函数以调用者身份执行(最小权限原则)→ 必须写
SQL SECURITY INVOKER - 你用自动化工具生成 DDL(如 CI/CD 脚本、schema diff 工具)→ 必须显式声明,避免工具误判或补全错误值
- 你函数里访问了
mysql系统库、性能视图或变量 → 显式写INVOKER可规避对DEFINER的额外权限要求 - 审计或合规要求明确权限边界 → 不允许依赖隐式行为,
SQL SECURITY是唯一可审计的安全上下文声明点
真正麻烦的从来不是多敲几个字,而是默认行为在不同 MySQL 版本、不同工具链、不同部署流程中表现不一致——SQL SECURITY 不写,它就在那儿,但没人能保证它下次还按你想的那样跑。


















