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 <em>.</em>是全局级别;若只需某库,用
ON <code>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;再检查函数体内所有表名是否带库名前缀(避免跨库时因权限粒度问题失败)。
函数权限的复杂性不在授权动作本身,而在于定义者语义、二进制日志策略、以及调用上下文的三重耦合。漏掉任意一环,都会表现为“明明给了权限却不能用”。
