开发账号不应拥有DROP、ALTER、GRANT OPTION等高危权限,日常仅需DML操作;应显式REVOKE剔除,并通过角色或精确到表的授权控制最小权限。

开发账号不该有 DROP、ALTER、GRANT OPTION 这些权限
开发日常只查、改测试数据,根本不需要删表、改库结构或授予权限。MySQL 默认不给这些权限,但很多人 GRANT 时顺手写 ALL PRIVILEGES 或漏掉 REVOKE,结果让开发能执行 DROP TABLE 或把权限转给别人。
实操建议:
- 创建账号后立刻用
REVOKE DROP, ALTER, CREATE, GRANT OPTION ON *.* FROM 'dev'@'192.168.10.%'显式剔除——别依赖“没给就不具备”这种侥幸 -
ALTER权限本身包含隐式DROP(比如RENAME TO实质是 drop + create),无法靠标准权限拆分,真要改结构就得走运维平台审批流程 - 如果用 MySQL 8.0+,可建角色隔离:比如
CREATE ROLE dev_dml只含SELECT, INSERT, UPDATE, DELETE,再GRANT dev_dml TO 'dev'@'192.168.10.%'
只读账号必须限制到具体库和表,不能用 db.*
写 GRANT SELECT ON app_test.* TO 'dev_ro'@'%' 看似安全,但一旦业务库混入敏感配置表(如 sys_config)、审计日志表或临时调试表,就全暴露了。更糟的是,app_test.* 还会连带放开对 information_schema 的默认可读——开发仍能 SELECT * FROM information_schema.tables 看到所有库名和表结构。
实操建议:
- 精确到表:
GRANT SELECT ON app_test.orders TO 'dev_ro'@'192.168.10.%',再多加一张表就再 GRANT 一次 - 老版本(REVOKE SELECT ON information_schema.* FROM 'dev_ro'@'192.168.10.%'(需 SUPER 权限才能执行)
- MySQL 8.0.29+ 可设
show_compatibility_56=OFF并配合REVOKE SELECT ON *.*,再单独授予业务表
IP 和认证细节常被跳过,但恰恰是第一道防线
很多团队配完 GRANT 就以为万事大吉,结果开发用手机热点连进来、或从办公网任意机器直连,权限再细也形同虚设。还有人忽略密码策略和匿名用户残留,让空密码账号成为后门。
实操建议:
- 主机名必须写死段:
'dev'@'192.168.10.%'比'dev'@'%'安全得多;生产环境甚至应限定到单 IP - 创建后立刻加固:
ALTER USER 'dev'@'192.168.10.%' PASSWORD EXPIRE INTERVAL 90 DAY,并确认validate_password策略已启用 - 运行
DROP USER IF EXISTS ''@'localhost'清掉安装时留下的匿名用户;检查SELECT User, Host FROM mysql.user确保没'root'@'%'
FLUSH PRIVILEGES 不是必需操作,但 SHOW GRANTS 必须验证
MySQL 5.7.6+ 和所有 8.0 版本中,GRANT 和 REVOKE 语句本身就会实时生效。FLUSH PRIVILEGES 不仅多余,还可能掩盖真实问题——比如你忘了给新用户设密码,flush 不会帮你补上,反而让你误以为“已经生效了”。
实操建议:
- 执行完授权后,立刻用
SHOW GRANTS FOR 'dev'@'192.168.10.%'查看实际生效权限,注意输出里有没有WITH GRANT OPTION - 不要信“我刚 GRANT 了”,要信
SHOW GRANTS的输出;它不显示动态权限(如BACKUP_ADMIN),8.0+ 需额外查mysql.role_edges - 如果开发连不上,优先查
SELECT host, user, authentication_string FROM mysql.user WHERE user='dev',确认 host 匹配且密码字段非空
真正卡住权限最小化的,往往不是语法不会写,而是没人去翻 mysql.general_log 看应用到底执行了哪些 SQL,也没人定期跑 SELECT User, Host, Select_priv, Insert_priv FROM mysql.user 扫描冗余账号。权限不是配一次就结束的事,是持续收敛的过程。


















