ERROR 1126 根本原因是 MySQL 未加载 UDF 插件模块,CREATE FUNCTION 仅绑定已加载符号,不负责加载动态库;必须先通过 INSTALL PLUGIN 或 --plugin-load-add 显式加载,且插件状态须为 ACTIVE。

为什么 CREATE FUNCTION 会报 ERROR 1126?
这是最常遇到的卡点:你写好了 .so(Linux)或 .dll(Windows)文件,执行 CREATE FUNCTION 却提示 Can't open shared library 'xxx.so' (errno: 127, cannot open shared object file) 或更隐蔽的 ERROR 1126 (HY000): Can't initialize function 'xxx'; Plugin is not loaded。根本原因不是文件路径错,而是 MySQL 根本没加载过这个插件模块——UDF 不是“用时才载入”,必须先注册为插件,再创建函数。
- MySQL 启动时不会自动扫描
plugin_dir下所有文件;必须显式执行INSTALL PLUGIN或通过配置加载 -
CREATE FUNCTION只负责把函数名、返回类型、参数绑定到已加载的符号,它不负责加载动态库 - 即使你用
mysqld --plugin-load-add=xxx.so启动,也得确认该插件状态为ACTIVE,查SELECT * FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'xxx';
如何安全启用 UDF 插件(plugin_load_add vs INSTALL PLUGIN)
两种方式都能让 MySQL 加载 UDF 动态库,但行为和权限要求完全不同。
-
--plugin-load-add=udf_name=xxx.so是启动参数,需重启 mysqld;适用于系统级预置、长期稳定使用的 UDF;加载失败会导致 mysqld 启动失败,排查靠错误日志里的Plugin 'xxx' init function returned error -
INSTALL PLUGIN udf_name SONAME 'xxx.so';是运行时 SQL,无需重启;但要求用户有INSERT权限在mysql.plugin表(通常是root或带SYSTEM_VARIABLES_ADMIN+CLONE_ADMIN的高权账号);卸载用UNINSTALL PLUGIN udf_name; - 注意
SONAME值必须和编译时指定的plugin_name一致(即my_udf_init函数所在结构体里的name字段),不是文件名 - Linux 下
xxx.so必须放在plugin_dir目录(查SHOW VARIABLES LIKE 'plugin_dir';),且 mysqld 进程要有读+执行权限(chmod +x)
UDF 函数创建后调用报 ERROR 1370:权限到底怎么设?
ERROR 1370 (42000): execute command denied to user 'xxx'@'%' for routine 'db_name.udf_func' 这个错容易误导人——它不是说你没权限执行函数,而是 MySQL 认为你没权限“访问这个函数对象”。UDF 权限模型和普通存储过程不同:它不走 mysql.procs_priv,而依赖函数定义时的 SQL SECURITY 和调用者的数据库级权限。
- UDF 没有
SQL SECURITY DEFINER/INVOKER选项,一律按调用者权限检查;所以用户必须对函数所在的数据库有EXECUTE权限(GRANT EXECUTE ON db_name.* TO 'user'@'%';) - 如果函数内部访问了某张表(比如做字符串处理时查字典表),调用者还得有对应表的
SELECT权限——UDF 不绕过行级/列级权限控制 - 别漏掉
USAGE权限:有些旧版本 MySQL 要求用户至少有USAGE才能解析函数名,否则直接报语法错
为什么 UDF 在本地能跑,上生产就段错误(SIGSEGV)?
这通常不是权限问题,而是环境差异导致的 ABI 不兼容或资源越界。UDF 是直接在 mysqld 进程地址空间里跑的 C/C++ 代码,任何野指针、未初始化内存、线程不安全操作都会让整个 MySQL 挂掉。
- 务必用和 MySQL 编译相同的 libc 版本和架构(x86_64 vs aarch64)编译 UDF;混用
glibc 2.34和2.28可能导致malloc行为异常 - 避免在 UDF 中使用
static全局变量保存状态——多个并发查询会互相覆盖;MySQL 不保证 UDF 函数调用是线程隔离的 - 不要调用
system()、popen()、网络 I/O 或长时间阻塞操作;UDF 应该是纯计算型、毫秒级完成 - 上线前用
valgrind --tool=memcheck --log-file=valgrind.log /usr/sbin/mysqld --defaults-file=/etc/my.cnf启动测试,捕获非法内存访问
UDF 的危险性不在权限配置多复杂,而在它把 C 级别的稳定性风险直接暴露给了 SQL 层——一个没检查空指针的 strcmp() 就能让 mysqld 进程崩掉,这种问题在线上很难复现,也很难从慢日志或 general log 里看出端倪。










