proxy用户必须显式开启check_proxy_users才生效,mysql默认关闭该机制;需配置check_proxy_users=on并重启或执行set persist check_proxy_users = on(8.0+),否则current_user()恒等于user(),代理无效。

Proxy用户必须显式开启check_proxy_users才生效
MySQL默认关闭PROXY权限机制,即使你执行了GRANT PROXY,服务端也不会检查或切换身份。不设这个变量,CURRENT_USER()永远等于USER(),代理形同虚设。
必须在MySQL配置文件中添加:check_proxy_users=ON,然后重启;或者动态执行:SET PERSIST check_proxy_users = ON(MySQL 8.0+)。注意:仅SET GLOBAL不够,它不持久化,重启后丢失。
- 验证是否生效:
SELECT @@global.check_proxy_users;返回ON才算成功 - 旧版MySQL(5.7)不支持
SET PERSIST,必须改my.cnf并重启 - 某些云厂商RDS默认禁用该参数且不允许修改,需确认控制台或文档是否开放
GRANT PROXY语法极易写错,host必须完全一致
PROXY授权不是普通权限,它对用户名和主机名的字面值敏感,差一个空格、大小写或通配符都会失败。错误示例:GRANT PROXY ON 'alice' TO 'app_user'@'%'——漏掉@'%'直接报错ERROR 1410。
正确写法必须严格匹配被代理用户的定义:
- 如果后端执行过
CREATE USER 'alice'@'localhost',那授权只能是GRANT PROXY ON 'alice'@'localhost' TO 'app_user'@'%' - 若被代理用户是
'alice'@'%',就不能写成'alice'@'127.0.0.1',哪怕网络层实际走的是本地回环 - 引号不能省:
'alice'@'%'≠alice@%(后者会被解析为语法错误)
客户端必须显式声明proxyUser,否则服务端不触发代理
ProxySQL或任何中间件都不会帮你透传或注入--proxy-user参数。这是客户端连接阶段的行为,服务端收到后才查mysql.proxies_priv表并切换上下文。
不同客户端写法差异大,容易漏配:
- 命令行:
mysql -uapp_user -p --proxy-user=alice - JDBC URL:
?user=app_user&password=xxx&proxyUser=alice(驱动≥8.0.22才支持) - Python
mysql-connector-python:connect(..., user='app_user', password='xxx', proxy_user='alice') - PHP PDO 不原生支持,需用
mysqli+mysqli_real_connect()手动传MYSQLI_CLIENT_INTERACTIVE等标志(实操复杂,不推荐)
验证是否成功:登录后立即执行SELECT USER(), CURRENT_USER();,前者应为app_user@client_ip,后者为alice@%——只有CURRENT_USER()决定权限边界。
PROXY权限无法嵌套或链式代理
MySQL只允许一级代理:A → B。如果你让app_user代理alice,再试图让alice代理bob,第二层会失败。服务端不递归解析,alice的PROXY权限对app_user无效。
更关键的是:被代理用户(如alice)本身必须有密码(MySQL 8.0+强制),且不能是匿名用户(''@'%')。否则即使授权成功,连接时也会报Access denied。
-
CREATE USER 'alice'@'%' IDENTIFIED BY 'strong_pwd';是前提 -
GRANT SELECT ON db.* TO 'alice'@'%';决定代理后的实际能力 -
app_user自身无需任何数据库权限,它只是“跳板”,但必须拥有PROXY权限
真正复杂的映射(比如按HTTP Header里的X-User动态代理)得靠应用层解析后再拼接连接参数,MySQL本身不提供运行时路由能力。











