为每个微服务配独立数据库、账号及精确到db_name.*的grant是唯一满足最小权限与跨服务隔离的方案;需显式指定host、强制require ssl、收回show databases、禁用all privileges,并通过api而非直连实现跨库访问。

直接为每个微服务配独立数据库 + 独立账号 + 精确到 db_name.* 的 GRANT,是唯一能防止跨服务读写、满足最小权限原则的方案。漏掉反引号、host 写成 %、或没收回 SHOW DATABASES,都会导致隔离失效。
CREATE USER 必须显式指定 host 和 REQUIRE SSL
微服务通常部署在固定子网(比如 K8s Pod CIDR 或 ECS 安全组),不能用 'svc_order'@'%' 这种写法。
-
CREATE USER 'svc_order'@'10.20.30.%' IDENTIFIED BY 'pwd' REQUIRE SSL PASSWORD EXPIRE INTERVAL 90 DAY;—— 强制走 TLS、密码定期轮换 - 本地开发调试时,
'svc_order'@'localhost'和'svc_order'@'127.0.0.1'是两个账号,连不上先查SELECT User, Host FROM mysql.user WHERE User = 'svc_order'; - 别跳过
REQUIRE SSL:哪怕内网通信,也防中间人劫持和配置误暴露
GRANT 必须带反引号和 .*,且禁用 ALL PRIVILEGES
权限不生效?八成是 GRANT 格式错了。MySQL 不认 db_order 这种裸名,只认 `db_order`.*。
- 正确写法:
GRANT SELECT, INSERT, UPDATE ON `db_order`.* TO 'svc_order'@'10.20.30.%';—— 反引号防短横线/数字库名解析失败,.*是语法必需 - 严禁
GRANT ALL PRIVILEGES ON db_order.*:ALL 包含DROP、ALTER、GRANT OPTION,一旦泄露等于交出整个库 - 如果服务要用存储过程,额外加
EXECUTE;要用临时表,加CREATE TEMPORARY TABLES;别多给
必须显式 REVOKE SHOW DATABASES 并验证连接串指定 database
即使只授了 db_order 权限,用户默认仍能在 SHOW DATABASES 里看到所有库名——这不是漏洞,是 MySQL 5.7/8.0 的设计行为。
- 补救命令:
REVOKE SHOW DATABASES ON *.* FROM 'svc_order'@'10.20.30.%';——REVOKE ALL不包含它,必须单收 - 连接字符串里强制指定
database=db_order,比如 JDBC:jdbc:mysql://db:3306/?useSSL=true&database=db_order - HikariCP 没内置 USE 支持,得用
ConnectionCustomizer.onAcquire执行USE db_order;Druid 可配connectionInitSqls=["USE db_order"],但要确认每次取连接都重置
跨库访问一律走 API,绝不直连授权
订单服务要查用户昵称,不代表它该有 db_user 的任何权限。授了就是把用户库白送给订单服务。
- 首选方案:用户服务暴露
/api/v1/users/{id}/basic,订单服务 HTTP 调用 - 次选方案(仅低延迟强耦合):在
db_order里建只读视图order_user_info,并GRANT SELECT ON `db_order`.order_user_info TO 'svc_order'@'10.20.30.%'; - 视图
DEFINER必须是低权限账号,严禁DEFINER = 'root'@'%',否则svc_order可借 root 身份执行任意 SQL
最易被忽略的是:建库建号必须由统一服务执行,禁止微服务启动时自建库或调用 CREATE DATABASE。权限边界不在 SQL 语句里,而在账号创建那一刻的 host、密码策略、SSL 要求和 SHOW DATABASES 收回动作上。











