error 1418 是 mysql 开启 binlog 后强制校验函数声明所致,必须显式声明 deterministic、no sql 或 reads sql data;同时需用户具备 create routine/alter routine 权限,并设 log_bin_trust_function_creators=on(推荐配置文件永久设置),而非依赖临时 set global。

CREATE FUNCTION 报 ERROR 1418 怎么办
这不是权限问题,而是 MySQL 的二进制日志安全机制在拦截。只要启用了 log_bin(主从复制或审计场景常见),且未显式允许函数创建,就会触发这个错误。
必须同时满足三项条件,CREATE FUNCTION 才能成功:
- 用户拥有
CREATE ROUTINE和ALTER ROUTINE权限(不是CREATE FUNCTION——这个权限根本不存在) - 全局变量
log_bin_trust_function_creators设为ON(需在my.cnf中配置并重启,SET GLOBAL不生效) - 函数体必须声明确定性属性:
DETERMINISTIC、NO SQL或READS SQL DATA
不建议直接设 log_bin_trust_function_creators=ON 全局放开。更稳妥的做法是:只对可信账号启用该参数,并配合 SQL SECURITY INVOKER 定义函数,让执行权限严格受限于调用者。
如何禁止用户加载 UDF 插件(.so/.dll)
CREATE FUNCTION ... SONAME 失败报 ERROR 1126 (HY000): Can't open shared library,表面是路径问题,实际是插件根本没被 MySQL 加载过。但真正要防提权,不能靠“让它失败”,而要让它“根本无法注册”。
最有效手段是切断加载入口:
- 启动时加
--disable-plugin=udf(MySQL 8.0.29+ 支持,推荐) - 或在
my.cnf的[mysqld]段设置plugin_dir=/nonexistent/path,让INSTALL PLUGIN和--plugin-load-add全部失效 - 删除
lib/plugin/udf_example.so等示例文件(但不要删lib/plugin/目录本身,否则影响其他插件)
注意:secure_file_priv=/dev/null 虽不能禁 UDF,但能堵住 SELECT ... INTO DUMPFILE 写入恶意 so 文件的常用路径,应一并配置。
FILE 权限和 UDF 提权的关系
FILE 权限本身不执行命令,但它和 UDF 组合就是完整攻击链:先用 SELECT ... INTO DUMPFILE 把编译好的 .so 写到 MySQL 可读目录(如 /var/lib/mysql-files/),再通过 CREATE FUNCTION 加载执行。
所以必须回收所有非必要账号的 FILE 权限:
- 检查谁有:
SELECT User,Host,File_priv FROM mysql.user WHERE File_priv='Y' - 回收命令:
REVOKE FILE ON *.* FROM 'user'@'host' - 注意:
FILE是全局权限,无法按库收缩;哪怕只读账号,只要带FILE,就可能被利用
业务真需要读写文件?应在应用层以最小权限账户处理,绝不经 SQL 透传路径或内容。
EXECUTE 权限对函数和 UDF 的作用不同
普通存储函数(CREATE FUNCTION)的执行权限走标准授权模型:必须显式 GRANT EXECUTE ON FUNCTION db.func_name TO 'user'@'host'。
但 UDF 不同——它不记录在 mysql.procs_priv,也不受 EXECUTE 授权控制。UDF 的调用权限取决于两件事:
- 用户是否对函数所在数据库有任意权限(哪怕只有
USAGE) - 函数定义时的
SQL SECURITY:若为DEFINER,则执行时以定义者身份访问数据;若为INVOKER,则检查调用者权限
也就是说,只要用户能连上库、知道 UDF 名字,且 MySQL 进程成功加载了那个 so 文件,就能调用——GRANT EXECUTE 对 UDF 无效。真正可控的点,只在加载环节(前两个副标题已覆盖)。











