修改mysql系统表(如mysql.func、mysql.proc)会破坏元数据一致性,导致用户自定义函数调用失败(如error 1305)、权限校验异常或服务中断;内置函数虽不依赖这些表,但在混合调用场景下可能受连带影响,且mysql_upgrade无法修复已存在的脏数据。

直接说结论:修改 MySQL 系统表(如 mysql.func、mysql.proc)会破坏函数元数据一致性,导致内置函数调用时解析失败或权限校验绕过失效,轻则报 ERROR 1305 (42000): FUNCTION xxx does not exist,重则引发服务异常或复制中断。
MySQL 内置函数不依赖系统表存储定义
内置函数(如 SUM()、DATE_ADD()、UUID())的实现硬编码在服务端源码中,并不在 mysql.func 表里注册。你手动往 mysql.func 插入或更新记录,对它们完全无效——MySQL 启动时根本不会读这张表来加载内置函数。
但问题出在「混合调用场景」:当 SQL 中同时用到内置函数和用户自定义函数(UDF),MySQL 的函数解析器会统一查 mysql.func 表做存在性校验和权限检查。如果该表结构损坏、字段值非法(如 type 不是 'function'、dl 路径为空或含控制字符)、或行被误删,整个函数查找链可能提前失败,连带让内置函数也“跟着报错不存在”。
- 典型现象:
SELECT NOW(), my_udf(1);报错FUNCTION my_udf does not exist,但单独SELECT NOW();正常;而SHOW FUNCTION STATUS;却看不到任何函数 - 根本原因:
mysql.func表损坏后,MySQL 在初始化函数缓存时直接跳过整张表,导致所有 UDF 不可见,且部分版本会连带抑制内置函数的正常解析上下文 - 验证方式:
SELECT COUNT(*) FROM mysql.func;返回 0 或明显异常数量(如负数、超大值),或DESCRIBE mysql.func;显示字段类型被意外修改(如name变成TEXT)
误改 mysql.proc 会影响函数调用权限校验
mysql.proc 存储的是存储过程和函数的定义元数据(包括 DETERMINISTIC、SQL_SECURITY、DEFINER 等关键字段)。虽然内置函数不在这张表里,但 MySQL 的权限检查模块(check_routine_access())在每次函数调用前,会统一走一套路径判断是否允许执行——它会尝试读取 mysql.proc 中对应记录来确认 SQL SECURITY 模式和 DEFINER 权限。一旦这张表被手动 UPDATE 过,可能出现:
-
DEFINER字段被改成不存在的账号(如'ghost'@'%'),触发权限检查时抛出内部错误,最终表现为ERROR 1418或静默拒绝 -
sql_mode相关字段(如character_set_client)被设为非法值,导致函数体解析阶段崩溃 - 行级
checksum或created时间戳异常,触发 MySQL 5.7+ 的元数据校验失败,直接禁用整个 routine 子系统
为什么修复不能只靠 mysql_upgrade
mysql_upgrade 主要处理系统表结构变更(如新增字段、调整索引),但它不会校验或修复已存在的脏数据。如果你手动执行过:
UPDATE mysql.func SET type = 'aggregate' WHERE name = 'COUNT';
或
DELETE FROM mysql.proc WHERE db = 'mysql';
这类操作,mysql_upgrade 完全无感知——它只比对表结构 DDL,不扫描行内容。
真正有效的修复路径是:
- 停库后用
mysqld --bootstrap --skip-grant-tables启动,手工还原mysql.func和mysql.proc到初始状态(从干净实例导出或官方 SQL 脚本重建) - 若只是 UDF 失效,可先用
DROP FUNCTION IF EXISTS xxx;清理残留,再用合法CREATE FUNCTION重建 - 严禁在运行中的生产库上直接
INSERT/UPDATE/DELETE系统表——所有 routine 管理必须通过 DDL 语句(CREATE/DROP/ALTER FUNCTION)
最易被忽略的一点:系统表修改后,即使重启 mysqld,函数缓存(func_cache)可能仍残留损坏状态。必须配合 FLUSH PRIVILEGES; + RESET QUERY CACHE;(若启用)+ 重新连接客户端,否则旧错误会持续复现。











