不能用 root 备份,因其拥有 DROP DATABASE 等高危权限,易导致误删;应创建最小权限账号,仅授予 SELECT、LOCK TABLES、SHOW VIEW、TRIGGER 权限,并按库显式授权。

为什么不能用 root 备份?
root 账号拥有 DROP DATABASE、DELETE、GRANT OPTION 等高危权限,一旦备份脚本被注入或误执行,可能直接清空库。实际生产中,mysqldump 只需要 SELECT(读表)、LOCK TABLES(防止写入导致不一致)、SHOW VIEW(导出视图)、TRIGGER(导出触发器)就够了——其他全是冗余风险。
创建最小权限账号的正确 SQL 语句
MySQL 8.0+ 和 5.7 的语法略有差异,关键在显式指定 LOCK TABLES 权限(它不属于全局权限,必须按库授予):
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'strong_password'; GRANT SELECT, LOCK TABLES, SHOW VIEW, TRIGGER ON `myapp_db`.* TO 'backup_user'@'localhost'; FLUSH PRIVILEGES;
注意点:
-
LOCK TABLES必须和SELECT同时授予,否则mysqldump --single-transaction会 fallback 到LOCK TABLES,报错Access denied; you need (at least one of) the LOCK TABLES privilege(s) for this operation - 不要用
GRANT ALL ON myapp_db.*—— 这会隐式包含ALTER、DROP,违背最小权限原则 - 如果备份多个库,需对每个库单独执行
GRANT ... ON `db_name`.*,MySQL 不支持通配符库名如`myapp_%`
验证权限是否生效
别只信 GRANT 语句执行成功。登录后手动测试最可靠:
mysql -u backup_user -p -e "SELECT COUNT(*) FROM myapp_db.users;" mysql -u backup_user -p -e "LOCK TABLES myapp_db.users READ;"
若第二条报错,说明 LOCK TABLES 没授对;若第一条查不到数据,检查是否漏了 SELECT 或库名大小写(Linux 下库名区分大小写)。
常见卡点:
- 用户 host 写成
'backup_user'@'%'但 mysqldump 从本地跑,实际连接的是localhost—— MySQL 把localhost当作 socket 连接,优先匹配'user'@'localhost'而非'user'@'%' - MySQL 8.0 默认认证插件是
caching_sha2_password,老版本客户端可能连不上,建用户时加IDENTIFIED WITH mysql_native_password兼容
mysqldump 命令里要关掉哪些默认行为?
即使权限收紧,mysqldump 默认仍可能触发越权操作。必须显式禁用:
- 去掉
--all-databases或--databases以外的库名参数,避免意外导出其他库 - 加
--skip-lock-tables是危险操作——除非你确认用了--single-transaction且引擎是 InnoDB;否则必须保留锁表行为 - 禁用
--events、--routines,除非明确需要导出存储过程——它们分别要求EVENT和EXECUTE权限,超出最小集 - 推荐最小安全命令:
mysqldump -u backup_user -p --single-transaction --routines=FALSE --events=FALSE --triggers myapp_db > backup.sql
真正难搞的是跨库依赖:比如 myapp_db 里有个视图引用了 sys 库的表。这时 SHOW VIEW 权限必须也给到 sys 库,但 sys 是系统库,MySQL 通常禁止对其授权——这种场景只能重构视图,或接受部分导出失败。


















