必须使用 mysqldump --routines 显式导出存储过程和函数,否则即使加 --all-databases 也不会导出;需注意 DEFINER 权限、SQL SECURITY 模式、MySQL 5.7/8.0 元数据差异及字符集兼容性问题。

导出存储过程和函数必须用 mysqldump --routines
默认 mysqldump 不导出存储过程和函数,哪怕加了 --all-databases 也没用。不加 --routines,dump 文件里只有表结构和数据,CREATE PROCEDURE 和 CREATE FUNCTION 一行都不会出现。
实操建议:
- 务必显式加上
--routines参数,例如:mysqldump -u root -p --routines --no-create-info --no-data mydb > routines.sql - 如果只导例程(不导表、不导数据),推荐搭配
--no-create-info和--no-data,避免干扰 -
--routines会同时导出PROCEDURE和FUNCTION,无法单独筛选;如需分离,得靠后续文本处理 - 注意权限:执行用户必须有
SELECT权限(对mysql.proc表),5.7+ 还需SELECT权限到mysql.system_tables(视版本而定)
DEFINER 是迁移失败最常见原因
导出的 CREATE PROCEDURE 语句里默认带 DEFINER=`user`@`host`。目标库若不存在该用户,或用户无对应权限,执行 source routines.sql 时会报错:ERROR 1449 (HY000): The user specified as a definer ('xxx'@'%') does not exist。
解决办法分场景:
- 开发/测试环境迁移:直接在 dump 前执行
SET GLOBAL log_bin_trust_function_creators = 1,并用--skip-definer(MySQL 8.0.26+)或手动替换DEFINER为当前用户 - 生产环境谨慎操作:先在目标库创建同名用户并赋权,再导入;或用
sed -i 's/DEFINER=`[^`]*`@`[^`]*`//g' routines.sql清除(等效于SQL SECURITY DEFINER变成INVOKER) - 注意
SQL SECURITY模式影响:DEFINER下过程以定义者权限运行,INVOKER下以调用者权限运行,权限逻辑可能变化
MySQL 5.7 与 8.0 的元数据差异会导致导入失败
8.0 默认开启 sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,且 mysql.proc 表结构已废弃,改用 mysql.routines 和 mysql.parameters。5.7 导出的 routine 在 8.0 导入时,可能因语法或权限校验更严而失败。
关键兼容点:
- 5.7 的
CREATE FUNCTION若含DETERMINISTIC、NO SQL或READS SQL DATA修饰符缺失,8.0 会拒绝创建(报错ERROR 1418),必须补全 - 8.0 中
log_bin_trust_function_creators默认为OFF,创建函数前必须设为ON,否则报ERROR 1418 - 字符集不一致时(如源库用
utf8mb4_0900_as_cs,目标库是utf8mb4_general_ci),ROUTINE_DEFINITION字段可能因排序规则冲突解析失败
不要依赖 SHOW CREATE PROCEDURE 批量导出
单个过程可用 SHOW CREATE PROCEDURE proc_name 查看定义,但没法直接导出全部——没有类似 SHOW CREATE ALL PROCEDURES 的语法。硬写脚本拼接容易漏掉注释、换行、特殊字符转义问题,还绕不开 DEFINER 和权限检查。
更稳的替代方案:
- 坚持用
mysqldump --routines,它是唯一官方支持的完整元数据导出方式 - 如需二次加工,从
information_schema.ROUTINES表查定义(ROUTINE_DEFINITION字段),但要注意该字段内容被截断(默认长度 2048 字符),大过程会丢代码 - 跨大版本迁移(如 5.6 → 8.0)前,先用
mysqlcheck --check-upgrade扫描兼容性风险
真正麻烦的不是导出动作本身,而是 DEFINER 权限链、sql_mode 校验、字符集隐式转换这三者交织在一起的问题。一个没对齐,source 就停在第 3 行。










