应为各环境创建独立用户并限制HOST和权限:dev/test/staging/prod分别建app_dev/app_test等账号,限定IP范围,禁用'%',开发账号仅授SELECT/INSERT/UPDATE且限dev_db,生产账号默认只读;启用skip-show-database隐藏库列表;密码通过mysql_config_editor(开发)或Secret挂载(生产)管理;授权后执行FLUSH PRIVILEGES并确保HOST完全匹配。

MySQL不同环境用同一实例时,怎么避免开发连上生产库
核心是别让所有环境共用 root 或同一个高权限账号。真实场景里,最常踩的坑是:本地开发、测试、预发、生产全连一个 MySQL 实例,只靠数据库名区分,结果某次 DELETE FROM user WHERE 1 在错环境执行了。
实操建议:
- 每个环境(dev / test / staging / prod)单独建用户,用户名带环境后缀,比如
app_dev、app_prod - 创建用户时强制指定
HOST,开发账号只允许从内网开发机 IP 或127.0.0.1连,生产账号只允许应用服务器 IP 段,禁用'%'通配 - 权限粒度按环境收紧:开发账号只给
SELECT、INSERT、UPDATE,禁止DROP、ALTER、CREATE;生产账号默认只读,写操作走专用运维账号 - 用
SHOW GRANTS FOR 'app_dev'@'192.168.10.%';定期核对,防止权限被误扩
如何让 dev 用户只能访问 dev\_db,prod 用户只能看到 prod\_db
MySQL 的库级权限本身不隔离 DB 列表——即使只授了 dev_db 权限,用户连上去执行 SHOW DATABASES 仍能看到所有库名(除非用 information_schema 权限控制)。这不是 bug,是设计如此。
实操建议:
- 启用
skip-show-database配置项(在my.cnf的[mysqld]下加),这样非SHOW DATABASES权限用户执行该命令直接报错ERROR 1227 (42501): Access denied - 给每个环境用户只授对应库的权限,例如:
GRANT SELECT,INSERT ON dev_db.* TO 'app_dev'@'192.168.10.%'; - 不要授
ON *.*,哪怕只是临时查问题;跨库查询需求,用视图或代理层解决,别放权 - 注意:MySQL 8.0+ 默认关闭
sql_mode中的NO_AUTO_CREATE_USER,建用户必须显式用CREATE USER,再GRANT,否则权限可能不生效
连接字符串里写死密码太危险,有没有更安全的多环境切换方式
把密码塞进 application.yml 或 .env 文件,在 Git 里传,等于把钥匙挂门口。尤其当 dev 和 prod 共用代码仓库时,风险指数级上升。
实操建议:
- 开发环境用
mysql_config_editor存加密登录信息:mysql_config_editor set --login-path=dev --host=127.0.0.1 --user=app_dev --password,然后程序里用--login-path=dev连,密码不落地 - 生产环境用文件系统权限控制:把数据库配置放在
/etc/my.cnf.d/app.conf,属主设为mysql:root,权限600,应用以mysql用户身份读取 - 容器化部署时,用 Secret 挂载配置文件,而非环境变量传密码;K8s 中避免
env.valueFrom.secretKeyRef直接注入到进程环境,优先用 volume mount - 所有配置文件中禁止出现
password =明文字段,MySQL 5.7+ 支持auth_socket插件,本地可免密登录,但仅限 Unix socket 场景
为什么 GRANT 后权限不生效,或者 SHOW GRANTS 看不到刚赋的权
不是语法错了,大概率是没刷权限表,或者用户 HOST 匹配失败。MySQL 权限缓存是会话级的,改完不刷新,新连接也拿不到最新权限。
常见错误现象:
- 执行
GRANT SELECT ON dev_db.* TO 'app_dev'@'localhost';,但应用用127.0.0.1连,实际匹配的是'app_dev'@'127.0.0.1',而这个账号根本不存在 - 改完权限后没运行
FLUSH PRIVILEGES;,旧连接还能用老权限,新连接却连不上(因为权限表没重载) - MySQL 8.0+ 使用角色(role),但没执行
SET DEFAULT ROLE,导致用户登录后角色未激活,权限不生效 -
CREATE USER和GRANT分两步执行时,如果中间有其他操作(比如DROP USER),要注意事务边界,MySQL 权限操作本身不支持回滚
真正关键的点在于:权限判断发生在连接建立瞬间,HOST 字符串必须完全一致,空格、大小写、IP 与域名解析结果,全都算不同账号。这点容易被忽略,查半天发现是 localhost 和 127.0.0.1 搞混了。


















