一、问题背景:备份恢复了,函数和存储过程却没了
在 MySQL 5.7 环境中,很多同学会遇到一个非常"反直觉"的现象:备份和恢复流程看起来完全正常,但恢复完成后,库里的函数、存储过程却全部丢失了。更让人困惑的是,备份文件本身并没有报错,恢复过程也没有任何异常提示。
本文从官方文档出发,先说明这个问题的成因,再通过"错误示范"和"正确示范"两组实操对比,给出可以直接落地的备份脚本与验证方法。
二、原因分析:为什么 mysqldump 会"丢"存储过程
先看官方文档给出的两条关键结论:
- 默认情况下,
mysqldump和mysqlpump都不会转储sys模式,详见 sys Schema Usage。 mysqldump默认不转储INFORMATION_SCHEMA、performance_schema和sysschema,详见 mysqldump。
也就是说,官方文档明确告诉我们:不会备份 sys 库 。但真正的问题并不止于此------在使用 mysqldump --all-databases 生成的备份 SQL 文件内部,会包含清空 mysql.proc 的语句,导致恢复后存储过程无法正常使用。这是一个 bug,并且只存在于 MySQL 5.7.x;MySQL 8.0.x 及 8.4 以上版本没有这个问题。


5.7版本,正常的备份恢复,会导致MySQL中的函数、存储过程丢失。
在MySQL官档中:
默认情况下,mysqldump和mysqlpump都不会转储sys模式。
https://dev.mysql.com/doc/refman/5.7/en/sys-schema-usage.html
mysqldump默认不转储"INFORMATION_SCHEMA"、"performance_schema" 和 "sys schema"。
https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html
官方文档明确的告诉我们不会备份 sys 库。
但在使用 mysqldump 在执行 --all-databases 生成的备份sql文件内部会清空 mysql.proc 导致 存储过程 无法正常使用;
这是一个bug,并且只存在于 MySQL 5.7.x
MySQL 8.0.x ,MySQL8.4以上版本没有这个问题(根据官方文档介绍MySQL 8.0 及以后版本:MySQL 进行了数据字典(Data Dictionary)重构)
需要注意的是,mysql.proc 表的存在与 MySQL 的版本密切相关:
MySQL 5.7 及更早版本:mysql.proc 是一个真实的物理系统表(早期使用 MyISAM 引擎,MariaDB 10.4+ 使用 Aria 引擎),可以直接被查询和操作。
MySQL 8.0 及以后版本:MySQL 进行了数据字典(Data Dictionary)重构,原有的 mysql.proc 物理表被移除,元数据统一迁移至基于 InnoDB 引擎的内部数据字典中(如 mysql.routines 和 mysql.parameters)。为了向后兼容,MySQL 8.0 提供了一个同名的只读视图,但不再推荐直接访问。
mysql> select count() from mysql.proc; --5.7版本(包括刚刚从5.7升级到8.0的情况,过一段时间这个表自动消失)正常情况下这里有数据
+----------+
| count() |
+----------+
| 48 |
+----------+
1 row in set (0.00 sec)
正确做法
select_databases="SELECT GROUP_CONCAT(schema_name SEPARATOR ' ') FROM INFORMATION_SCHEMA.SCHEMATA where SCHEMA_NAME NOT IN ('performance_schema','information_schema');"
db_list=mysql --login-path=root -NBe "$select_databases"
echo $db_list
执行备份
mysqldump --login-path=root -R -F --master-data=2 --single-transaction --max_allowed_packet=1024M --log-error=mysqldump_error.log --databases $db_list --triggers --routines --events 2> /dev/null | gzip > all_bak_date +%Y%m%d.sql.gz
单独备份sys/mysql模式
/usr/local/mysql/bin/mysqldump -uroot -p****** --databases sys --single-transaction --triggers --routines --events --result-file=/backup/sys_date +%Y%m%d.sql
/usr/local/mysql/bin/mysqldump -uroot -p'123qqq...A' --databases mysql --single-transaction --triggers --routines --events --result-file=/backup/mysql_date +%Y%m%d.sql
验证备份
grep "Current Database" all_bak_date +%Y%m%d.sql
egrep "USE `mysql`;|IF EXISTS `proc`;|INSERT INTO `proc` VALUES" all_bak_date +%Y%m%d.sql
三、版本差异:mysql.proc 表的前世今生
需要注意的是,mysql.proc 表的存在与 MySQL 的版本密切相关:
- MySQL 5.7 及更早版本 :
mysql.proc是一个真实的物理系统表(早期使用 MyISAM 引擎,MariaDB 10.4+ 使用 Aria 引擎),可以直接被查询和操作。 - MySQL 8.0 及以后版本 :MySQL 进行了数据字典(Data Dictionary)重构,原有的
mysql.proc物理表被移除,元数据统一迁移至基于 InnoDB 引擎的内部数据字典中(如mysql.routines和mysql.parameters)。为了向后兼容,MySQL 8.0 提供了一个同名的只读视图,但不再推荐直接访问。
因此,在 5.7 上排查问题时,可以直接查询 mysql.proc 确认存储过程数量:
select count() from mysql.proc;
错误示范(--all-databases)







正确示范(单独指定databases)
[root@itpuxdb01 ~]# cat mysql_backup.sh
select_databases="SELECT GROUP_CONCAT(schema_name SEPARATOR ' ') FROM INFORMATION_SCHEMA.SCHEMATA where SCHEMA_NAME NOT IN ('performance_schema','information_schema');"
db_list=mysql -uroot -p'******' -h127.0.0.1 -P3306 -NBe "$select_databases"
echo ========================
echo $db_list
echo ========================
mysql 5.7.25 mysql.proc
/usr/local/mysql/bin/mysqldump -uroot -p'******' -h127.0.0.1 -P3306
-R -F --master-data=2 --single-transaction --max_allowed_packet=1024M
--log-error=mysqldump_error.log --databases $db_list
--triggers --routines --events --hex-blob > all_bak_date +%Y%m%d.sql
如果要压缩添加以下参数
--log-error=mysqldump_error.log
2> /dev/null | gzip > all_bak_date +%Y%m%d.sql.gz
单独备份sys/mysql模式
/usr/local/mysql/bin/mysqldump -uroot -p'' --databases sys --single-transaction --triggers --routines --events --result-file=/backup/sys_date +%Y%m%d.sql
/usr/local/mysql/bin/mysqldump -uroot -p'' --databases mysql --single-transaction --triggers --routines --events --result-file=/backup/mysql_date +%Y%m%d.sql
验证备份
grep "Current Database" all_bak_20261024.sql
egrep "USE `mysql`;|IF EXISTS `proc`;|INSERT INTO `proc` VALUES" all_bak_20261024.sql



四、mysqldump8.0 全备还原仍有几个容易踩的坑
但 8.0 全备还原仍有几个容易踩的坑
- mysqldump --all-databases 默认不导出存储过程/函数/事件
必须显式加 --routines --events,否则还原后业务库的存储过程、函数、事件会丢失。 - sys 库本身默认也不被 mysqldump 导出
官方文档明确说明 mysqldump / mysqlpump 默认不 dump sys schema。 不过 8.0 的 sys 视图是纯 SQL 视图,不依赖 mysql.proc 里的 routines,所以不会出现 5.7 那种 ERROR 1356 连锁失效。 - DEFINER 权限问题更常见
8.0 对 DEFINER 校验更严格,如果备份里有 DEFINER='xxx'@'yyy' 而目标库没有该用户,导入会报 ERROR 1449 或 ERROR 1227。可以用 --skip-definer(8.0.26+)或导入前建好对应用户。
8.0 推荐的全备命令
/usr/local/mysql/bin/mysqldump --all-databases \
--set-gtid-purged=OFF \
-R -F --source-data=2 \
--single-transaction \
--routines \
--events \
--triggers \
--hex-blob \
--max_allowed_packet=256M \
--log-error=mysqldump_error.log \
2> /dev/null | gzip > all_bak_`date +%Y%m%d`.sql.gz
如果你还希望 sys 库也一起备份(虽然 8.0 不必须),可以额外:
/usr/local/mysql/bin/mysqldump --databases --routines sys > sys_dump.sql
五、一句话总结
- 5.7:mysqldump -A 还原会清空 mysql.proc → sys 库失效,是已知 bug。
- 8.0+:mysql.proc 已移除,该 bug 不存在;但要注意加 --routines --events,以及 DEFINER 权限兼容性。