MySQL函数创建需同时满足:用户拥有CREATE ROUTINE和ALTER ROUTINE权限;log_bin_trust_function_creators=1或未启用binlog;函数须显式声明DETERMINISTIC、NO SQL或READS SQL DATA及SQL SECURITY。

MySQL 函数创建权限到底要哪些?
普通用户执行 CREATE FUNCTION 会直接报错:ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration,但这只是表象。真正卡住的是权限和全局配置双重限制。
必须同时满足:
- 用户拥有
CREATE ROUTINE权限(不是CREATE FUNCTION—— 这个权限不存在) - 用户拥有
ALTER ROUTINE权限(后续修改函数需要) - MySQL 启动时未设置
--log-bin,或已显式设置log_bin_trust_function_creators=1
否则即使权限全开,也会因二进制日志安全机制被拒绝。
如何安全开启自定义函数支持?
不建议直接设 log_bin_trust_function_creators=1 后全局放行。更稳妥的做法是:
- 仅在确需函数复制的主从环境中启用该参数,且只对可信账号授权
- 在
my.cnf中添加:[mysqld] log_bin_trust_function_creators = ON
- 修改后必须重启 MySQL(动态 SET 不生效)
- 随后授予具体用户权限:
GRANT CREATE ROUTINE, ALTER ROUTINE ON *.* TO 'dev_user'@'localhost';
注意:ON . 是全局级别;若只需某库,用 ON 即可,但函数本身仍可跨库调用。app_db.*
函数体里访问数据表,权限怎么算?
函数运行时的权限,取决于定义者(DEFINER) 而非调用者(INVOKER),这是关键误区。
- 若定义为
DEFINER = 'admin'@'%',则函数内所有SELECT/INSERT操作都以admin权限执行 - 若定义为
SQL SECURITY INVOKER,则权限检查发生在调用时刻,依赖当前用户对目标表的权限
生产环境强烈建议显式声明:
CREATE FUNCTION get_user_name(uid INT) RETURNS VARCHAR(50) READS SQL DATA SQL SECURITY DEFINER ...
否则默认是 DEFINER,但若定义者账号后来被删或密码过期,函数会直接失效,且错误提示极不直观(常表现为空结果或 NULL)。
为什么函数在命令行能跑,Java 应用却报错?
常见于 JDBC 连接串未指定 allowMultiQueries=true 或未关闭 prepared statement 缓存,但更隐蔽的原因是:
- MySQL 8.0+ 默认禁用
CREATE FUNCTION的自动权限继承 - 应用连接使用的账号可能没被显式授予
CREATE ROUTINE,即使它是root降权后的账号 - 函数中用了
SELECT ... INTO但目标变量未声明,错误被 JDBC 吞掉,只返回空结果
排查时先在 MySQL 客户端用同一账号执行:
SHOW GRANTS FOR CURRENT_USER;
CREATE ROUTINE;再检查函数体内所有表名是否带库名前缀(避免跨库时因权限粒度问题失败)。
函数权限的复杂性不在授权动作本身,而在于定义者语义、二进制日志策略、以及调用上下文的三重耦合。漏掉任意一环,都会表现为“明明给了权限却不能用”。










