MySQL账号权限脚本应使用幂等的.sql文件,统一用CREATE USER IF NOT EXISTS + GRANT + FLUSH PRIVILEGES,密码指定mysql_native_password,Host按环境变量限定,8.0+禁用手动操作mysql.user表。

MySQL账号权限脚本该用什么格式写
直接用 .sql 文件写最稳妥,别用 ORM 或配置文件生成账号逻辑。MySQL 的账号体系(mysql.user 表)和权限模型(GRANT 语句)本身不支持“增量 diff”,脚本必须是幂等的、可重放的。
常见错误:把账号创建和权限授予拆成两个独立脚本,导致重复执行时报 ERROR 1396 (HY000): Operation CREATE USER failed;或者用 DROP USER IF EXISTS 再 CREATE USER,但忘了 FLUSH PRIVILEGES,权限不生效。
- 所有账号操作统一用
CREATE USER IF NOT EXISTS+GRANT+FLUSH PRIVILEGES - 密码必须用
IDENTIFIED WITH mysql_native_password BY 'xxx'(尤其 MySQL 8.0+,默认caching_sha2_password会导致旧客户端连不上) - 权限范围尽量具体,比如
GRANT SELECT, INSERT ON mydb.orders TO 'app_rw'@'10.20.%',别写GRANT ALL ON *.*
怎么让账号脚本支持多环境(dev/staging/prod)
靠 SQL 脚本本身做不到条件分支,得靠外部驱动 —— 推荐用 shell 包一层,传参控制 host 和密码,而不是维护三套几乎一样的 .sql 文件。
容易踩的坑:在脚本里硬编码 'localhost',结果部署到容器或远程 DB 时权限不匹配;或者用 '%' 太宽泛,CI/CD 流水线一跑,测试账号能连生产库。
- 账号 Host 段统一用变量替换,例如
sed "s/{DB_HOST}/$DB_HOST/g" user-prod.sql | mysql -u root -p - 敏感密码绝不进 Git,通过
mysql --defaults-file或环境变量注入(mysql -u root --password=$MYSQL_ROOT_PWD) - dev 环境用
'127.0.0.1'或'localhost',staging/prod 严格限定 CIDR,如'10.100.5.0/24'
MySQL 8.0 权限变更带来的兼容性问题
MySQL 8.0 把权限表从 MyISAM 改成 InnoDB,mysql.user 不再允许直接 INSERT/UPDATE,必须用 CREATE USER 和 GRANT。老脚本如果还写 INSERT INTO mysql.user,会报 ERROR 1785 (HY000): Statement violates GTID consistency 或直接拒绝执行。
另一个坑是角色(role)功能上线后,有人误以为能替代账号管理 —— 但角色不能跨实例复用,且无法导出为纯 SQL,不适合代码库版本控制。
- 彻底弃用对
mysql.user表的手动 DML 操作 - 避免用
CREATE ROLE+GRANT role TO user做主账号方案,CI 流水线重放时角色依赖顺序难保证 - 检查
default_authentication_plugin,若为caching_sha2_password,应用连接字符串需显式指定?serverTimezone=UTC&allowPublicKeyRetrieval=true
账号脚本如何纳入 CI/CD 流程验证
关键不是“能不能执行”,而是“执行后权限是否符合预期”。单纯 mysql -e "SELECT User,Host FROM mysql.user" 没用,得查 INFORMATION_SCHEMA.ROLE_TABLE_GRANTS(8.0)或 SHOW GRANTS FOR 'user'@'host' 输出做文本比对。
最容易被忽略的一点:权限脚本执行成功 ≠ 应用能连上。网络策略、SSL 要求、max_connections 限制这些不在 SQL 范围内,但失败现象会误判为账号问题。
- CI 阶段加一个验证步骤:
mysql -u test_user -ptest_pass -h $DB_HOST -e "SELECT 1" && echo "connect ok" - 用
mysqldump --no-data --skip-triggers --compact mysql.user生成账号快照,和 baseline diff(注意排除password_last_changed这类时间戳字段) - 禁止在 prod 环境自动执行账号变更,必须人工确认 + 二次密码校验(比如要求输入
PROD_APPROVAL_TOKEN)


















