在多租户或研发共用数据库的场景里,直接把MySQL账号发给业务方会带来越权风险。ProxySQL作为MySQL协议兼容的代理层,可以把连接、路由和权限控制从数据库本身剥离出来,在中间件层做统一的准入与转发。

为什么要在ProxySQL层做权限隔离
MySQL自身的权限系统是基于用户名、主机和库表授权的,粒度可控但管理成本高。每当新业务接入,DBA要在后端执行CREATE USER和GRANT,密码散落在多个应用配置中,且难以按SQL类型动态拦截。ProxySQL把前端连接和后端连接解耦,前端应用只连代理,真正的数据库账号由代理持有,从物理上避免了应用直连带来的凭证泄露。
更重要的是,ProxySQL的路由规则是运行期可热加载的。比如临时把某个报表账号的查询全部导到从库,或者拒绝包含DELETE的语句,不需要改MySQL权限表,也不会中断现有连接。这种灵活性让权限隔离从静态配置变成可编排的策略。
核心配置模块与权限映射
ProxySQL的权限隔离主要依赖三个表:mysql_users定义前端登录身份,mysql_servers登记后端节点,mysql_query_rules编写路由与拦截逻辑。前端用户并不需要对应一个同名的MySQL用户,代理会用自身维护的后端账户去真实执行。
下面是一段典型的用户与服务器注册脚本,先放入内存再持久化:
INSERT INTO mysql_users (username, password, default_hostgroup, active)
VALUES ('app_read', 'readpwd123', 10, 1);
INSERT INTO mysql_servers (hostgroup_id, hostname, port)
VALUES (10, '192.168.0.1', 3306), (20, '192.168.0.2', 3306);
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
这里app_read是应用使用的账号,默认进入hostgroup 10(可读从库)。真正的MySQL后端账号在另一张表或复用同一密码,应用永远不知道真实凭证。
用查询规则实现路由与拦截
路由规则是权限隔离的关键。我们可以通过正则匹配SQL文本,把写操作拒绝掉,或者把特定库流量导向专用组。以下规则拒绝非只读账号执行修改语句:
INSERT INTO mysql_query_rules (rule_id, active, username, match_pattern, apply) VALUES (1, 1, 'app_read', '^SELECT', 1); INSERT INTO mysql_query_rules (rule_id, active, username, match_pattern, apply) VALUES (2, 1, 'app_read', '^(INSERT|UPDATE|DELETE|DROP)', 0); LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;
第一条规则让app_read的SELECT正常走默认组;第二条匹配到写语句时apply=0表示不应用任何路由,结合默认禁止策略可返回错误。实际生产中常配合error_msg字段给出明确拒绝原因。
如果要把报表库report_db的查询强制走从库组20,可加一条更高优先级的规则:
INSERT INTO mysql_query_rules (rule_id, active, username, schemaname, destination_hostgroup, apply) VALUES (3, 1, 'app_read', 'report_db', 20, 1); LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;事务与越权访问的边界
需要注意,ProxySQL是基于每条SQL做路由的,如果一个事务里先写主库再读从库,可能读到旧数据。对权限隔离而言,应在规则层面对开启事务的账号限定单一hostgroup,避免跨组。例如给运维账号只允许hostgroup 10,从应用侧杜绝越权切库。
另外,前端用户如果知道后端拓扑,仍可能通过
USE语句切库。可以在规则里用match_pattern匹配^USEs+secret_db并拦截,从而把敏感库的访问留在代理层白名单内。这样即便MySQL后端账号有更广权限,经过ProxySQL也已被收敛。方案对比与落地建议
和直接在MySQL建只读账号相比,ProxySQL方案多了一次网络跳转,但换来统一治理。下表列出差异:
| 维度 | MySQL原生只读账号 | ProxySQL路由隔离 |
|---|---|---|
| 凭证管理 | 密码分布在应用 | 代理持有,应用无感知 |
| 动态拦截 | 需改权限表并刷权限 | 规则热加载秒级生效 |
| 跨库控制 | 靠GRANT粒度 | 靠正则与schemaname规则 |
| 连接收敛 | 应用直连,连接数难控 | 代理池化,后端连接可控 |
建议先把所有应用流量切到ProxySQL,再按业务域拆分前端账号,用查询规则逐步收紧。待规则稳定后,后端MySQL可回收除代理外所有远程账号,彻底完成中间件层权限隔离。