备份mysql系统库必须加--skip-lock-tables,因权限表不支持lock tables会导致卡住或报错;需select权限且推荐root或专用账号;应明确指定user、db等权限表而非--all-databases;不可加--no-data;脚本须检查退出码并验证备份内容;还原时禁止直接source到运行实例。

mysqldump 备份 mysql 系统库要加 --skip-lock-tables
直接用 mysqldump mysql 会卡住或报错,因为 mysql 库里的表(比如 user、db)默认被加了全局读锁,而 mysqldump 默认尝试加锁保证一致性——但系统表不支持常规 LOCK TABLES,导致连接挂起或报 ERROR 1045 (28000): Access denied 或 ERROR 1142: SELECT command denied(即使有权限也可能触发)。
实操建议:
- 必须加上
--skip-lock-tables,避免锁冲突;--single-transaction对系统库无效,别用 - 需要
SELECT权限在mysql库所有表上,推荐用 root 或带SELECTonmysql.*的专用账号 - 命令示例:
mysqldump --skip-lock-tables -u root -p mysql > mysql_system_$(date +%F).sql - 如果提示
Access denied for user ... to database 'mysql',不是密码错,而是账号没显式授权:执行GRANT SELECT ON mysql.* TO 'backup_user'@'localhost'; FLUSH PRIVILEGES;
只导出权限相关表结构,不用 --all-databases
--all-databases 会把业务库全拉进来,和“只备份权限表结构”目标冲突,而且可能因字符集、存储引擎差异导致还原失败。真正需要的只是 mysql 库里那几张权限元数据表。
实操建议:
- 明确指定表名更安全:
mysqldump --skip-lock-tables -u root -p mysql user db tables_priv columns_priv procs_priv proxies_priv > mysql_grants_$(date +%F).sql - 不需要导出
help_topic、time_zone*、innodb_index_stats等非权限表,它们和权限管理无关 - 加
--no-data只导结构?不行——权限表结构本身不重要,关键是里面的行数据(即 grant 记录),所以必须保留--no-data不启用 - 如果只想看结构用于比对,可单独跑:
mysqldump --no-data --skip-lock-tables -u root -p mysql user > user_schema.sql
定期备份脚本里要检查 mysqldump 退出码
权限备份看似简单,但一旦 mysqldump 因权限不足、连接中断或磁盘满而静默失败,后续还原时才发现权限全丢了,问题就大了。
实操建议:
- shell 脚本里必须判断返回值:
if ! mysqldump --skip-lock-tables -u root -p"$PASS" mysql user db > backup.sql; then echo "dump failed"; exit 1; fi - 避免用重定向掩盖错误:
mysqldump ... > file.log 2>&1会吞掉关键报错,应分开记录:2>dump.err并检查文件大小是否为 0 - 加
--verbose仅调试用,生产脚本关掉,否则日志爆炸;可用--silent减少干扰输出 - 备份后建议快速验证:用
head -20 backup.sql | grep -q "INSERT INTO.*user"确认内容写入正常
还原权限表不能直接 source 到运行中的实例
线上 MySQL 实例正在用 mysql.user 表鉴权,如果直接 source mysql_grants.sql,可能中途覆盖当前生效的权限,导致连接断开、应用报 Access denied,甚至把自己锁在外面。
实操建议:
- 还原前必须停掉所有客户端连接,或先用
FLUSH TABLES WITH READ LOCK(注意:这会阻塞 DML,慎用) - 更稳妥做法:在从库或离线环境还原,确认 SQL 无误后再同步到主库;或用
mysql -u root -p mysql ,但确保该命令执行期间没人改权限 - 不要用
DROP DATABASE mysql再重建——系统库结构受版本强约束,MySQL 升级后表结构可能变化,硬删会导致实例无法启动 - 还原后务必执行
FLUSH PRIVILEGES;,否则新导入的权限不会生效
实际操作中最容易被忽略的是:备份脚本没设超时、没校验输出大小、也没做权限表内容快照比对。一旦某次备份空了,你得靠日志倒查,而不是等出事才翻。











