mysql ci/cd账号必须遵循最小权限原则:仅授予执行迁移脚本和查版本状态所必需的、精确到表名与操作类型的权限,如单独授权flyway_schema_history表的select/insert/update、业务表指定dml、mysql.db/user表有限select等,限定ip、强制caching_sha2_password插件、外部注入密码,并通过完整部署流程验证权限有效性。

直接给CI/CD账号授ALL PRIVILEGES或用root跑部署,等于把数据库的物理钥匙塞进流水线日志里——一次构建机泄露,整个库就裸奔。真实可用的最小权限不是“少给点”,而是只给它执行迁移脚本和查版本状态这两件事必需的、精确到表名和操作类型的权限。
只授权具体表和具体操作,别用database.*模糊匹配
CI/CD账号不该靠通配符继承权限。比如写成GRANT SELECT, INSERT ON myapp.* TO 'ci_deploy'@'10.20.30.40',后续在myapp下新建一张表,权限自动生效,这违反最小权限原则。
- Flyway必须读写的
flyway_schema_history表:单独授SELECT, INSERT, UPDATE - 业务表(如
users、orders):只授迁移脚本实际涉及的DML,例如GRANT INSERT, UPDATE ON myapp.users TO 'ci_deploy'@'10.20.30.40',不加DELETE除非明确需要回滚数据 - 存储过程部署需
EXECUTE权限,但仅限具体过程名:GRANT EXECUTE ON PROCEDURE myapp.calc_revenue TO 'ci_deploy'@'10.20.30.40'
前置检查要用的权限不能漏,但得控制粒度
流水线常在执行前跑SHOW DATABASES或SELECT VERSION()做环境校验,这些操作背后其实依赖mysql系统库里的表,但不能因此直接给mysql.*全权。
- 显式授予
SELECT权限到mysql.db和mysql.user表(仅限查询,不包含password字段) - 避免授
SELECT给mysql.user的authentication_string列——现代MySQL 8.0+已弃用Password字段,但误授仍可能暴露哈希值 -
information_schema只需SELECT,且仅限必要视图,如SCHEMATA、TABLES,不开放PROCESSLIST或USER_PRIVILEGES
连接来源、密码插件、凭据注入三者必须绑定
权限再细,连不上或连错方式也白搭。MySQL 8.0+默认caching_sha2_password插件和新版客户端(如mysql2 v3+)存在握手兼容问题,而硬编码密码是高危操作。
- 账号必须限定IP:
'ci_deploy'@'10.20.30.40',禁用'ci_deploy'@'%' - 创建用户时强制指定插件:
CREATE USER 'ci_deploy'@'10.20.30.40' IDENTIFIED WITH caching_sha2_password BY 'xxx' - 密码绝不能写在
.gitlab-ci.yml或Jenkinsfile里,应通过CI平台的Secrets管理功能注入,或使用MYSQL_PWD环境变量配合--defaults-file方式加载 - 不用
FLUSH PRIVILEGES——GRANT语句执行后权限立即生效,手动刷反而掩盖语法错误
最容易被忽略的是:权限配置完必须走一遍完整部署流程验证,而不是只测单条SQL。比如Flyway执行repair会尝试DELETE历史记录,如果没开对应权限,它不会报错,而是静默跳过——直到某次真正需要修复时才发现失败。最小权限不是设完就完事,是每次迁移脚本变更后都要重验边界行为。











