开发环境账号严禁出现在生产库上,必须上线前扫描并阻断发布;dev_user与prod_app须为独立账号;权限需按环境精确粒度授予,禁止跨环境复用或宽泛host。

开发环境账号不能出现在生产库上
生产库里查到 dev_user,就等于把测试钥匙插进了保险柜锁孔。哪怕它只读、密码复杂、host限制在127.0.0.1,只要存在,就可能被误连、被泄露、被绕过代理直连。
- 上线前必须执行:
SELECT user, host FROM mysql.user WHERE user = 'dev_user';扫描所有生产实例,脚本返回非空即阻断发布 - 禁止用同一用户名+不同密码区分环境——
dev_user和prod_app必须是两个独立账号,不能共用user字段 - Docker 或本地开发环境可加
--skip-grant-tables临时跳过权限校验,但仅限离线调试,绝不能暴露在任何网络可达容器中
GRANT语句必须按环境写死权限粒度
开发环境给 ALL PRIVILEGES 看似省事,实则掩盖真实依赖;生产环境用 GRANT ALL ON *.* 则是裸奔。
- 开发账号只授:
SELECT,INSERT,UPDATE,DELETE,CREATE TEMPORARY TABLES;禁用DROP,ALTER,INDEX,GRANT OPTION - 生产账号严格按角色拆分:
app_rw(业务库读写)、app_ro(只读从库)、backup(限定 IP 的备份专用账号) - 显式限定库名:
GRANT SELECT ON myapp_production.* TO 'app_ro'@'10.20.30.%';,不写*或*.*
host 匹配错误是权限不生效的高频原因
MySQL 权限匹配不是模糊匹配,而是“最长 host 前缀优先”。'app'@'10.20.%' 和 'app'@'10.20.30.45' 是两条独立记录,后者优先级更高——但如果你没确认应用真实来源 IP,就容易填错。
- 查真实连接来源:
SELECT host FROM information_schema.processlist WHERE user = 'app_rw'; - 查权限是否命中:
SHOW GRANTS FOR 'app_rw'@'10.20.30.45';(注意填实际 IP,不是通配符) - 禁止用
'app_rw'@'%',哪怕加了REQUIRE SSL——改用最小网段,如'app_rw'@'10.20.30.%' - 若走代理或 K8s Pod 网络,host 可能是 VIP 或内网 IP,需提前采集再配置,不能靠 DNS 名猜
权限迁移不能直接复制 mysql.user 表
直接 mysqldump mysql.user 导出再导入,大概率带入空密码、'%'@'%'、过期账号、caching_sha2_password 插件等脏数据,轻则连不上,重则覆盖已有用户。
- 推荐方式:
pt-show-grants --user=root --password=xxx --host=dev-db > grants_dev.sql,再人工编辑剔除测试账号、补REQUIRE SSL、调 host 网段 - 若必须导表,命令要限定:
mysqldump -u root -p --databases mysql --tables user db tables_priv > priv_dump.sql - 导入前必须删掉含
root、test、'%'的行;MySQL 8.0+ 用户导入 5.7 目标库时,需把plugin字段从caching_sha2_password改为mysql_native_password - 导入后务必执行:
FLUSH PRIVILEGES;—— 直接写系统表不会自动生效
真正卡住风险的不是权限多难配,而是开发账号残留、host 写宽、plugin 不兼容这三处细节。它们不出问题时毫无存在感,一出就是线上事故。











