在MySQL中怎么创建具有受限权限的只读账号?

作者:袖梨 2026-07-16
MySQL权限是白名单机制,必须显式授予GRANT SELECT ON mydb.才实现真正只读;GRANT SELECT ON .*会暴露系统库结构,存在信息泄露风险。

GRANT SELECT 必须指定库表范围,不能靠“没给写权限”假设安全

MySQL 权限是白名单机制:只授 GRANT SELECT ON mydb.* 才算真正只读;GRANT SELECT ON *.* 会暴露 mysqlperformance_schema 等系统库结构,存在信息泄露风险。常见错误包括:

  • 用单引号包库名,如 'my-db'.* → 语法错误,正确写法是 `my-db`.* 或无特殊字符时直接写 mydb.*
  • 跨库 JOIN 查询失败却以为权限正常 → SELECT * FROM db1.t1 JOIN db2.t2 要求对 db1.*db2.* 都显式执行 GRANT SELECT
  • 误以为 REVOKE INSERT 等操作能“加固”只读 → 实际上没授过的权限无需回收,反而容易漏掉 TRUNCATELOCK TABLES 等隐式写权限

USAGE 权限必须单独授予,否则用户连不上

GRANT SELECT 只管“能做什么”,不管“能不能登录”。没有 USAGE,认证通过后立刻断连,报错 ERROR 1045 (28000): Access denied,哪怕密码完全正确。MySQL 8.0+ 不再自动附带 USAGE,这步不能跳。

  • 补授权语句:GRANT USAGE ON *.* TO 'ro_user'@'192.168.10.%'
  • USAGE 是纯连接权,不带任何操作能力,必须和 SELECT 分开授予
  • 主机名别用 '%' 放行所有 IP,生产环境建议限定内网段,如 '192.168.10.%'

SHOW CREATE TABLE 失败?缺 INFORMATION_SCHEMA 显式授权

很多 ORM、监控工具或 DBA 手动查表结构时会执行 SHOW CREATE TABLE t1,这条语句底层依赖对 information_schema.TABLESinformation_schema.COLUMNSSELECT 权限。MySQL 5.7 默认允许访问,但 8.0+ 默认收紧。

  • 只授了业务库权限,SHOW CREATE TABLE 就会报 ERROR 1142 (42000): SELECT command denied
  • 解决方法:GRANT SELECT ON INFORMATION_SCHEMA.* TO 'ro_user'@'192.168.10.%'
  • 不需要全量开放 performance_schemasys,除非明确需要其视图

CREATE USER 和 GRANT 必须分两步,不能合在一条语句里

MySQL 5.7 及以后不支持在 CREATE USER 时直接带 GRANT,强行写成一句会报错:ERROR 1064 (42000): You have an error in your SQL syntax

  • 正确写法分两步:CREATE USER 'ro_user'@'192.168.10.%' IDENTIFIED BY 'strong-pass-2024';,再 GRANT SELECT ON myapp_db.* TO 'ro_user'@'192.168.10.%';
  • 密码必须用单引号包裹,且不能是纯数字或简单字符串;MySQL 8.0+ 默认校验密码强度,太弱会拒绝创建
  • 执行完 GRANT 后无需 FLUSH PRIVILEGES(除非你手动改过 mysql.user 表),GRANT 自动刷新权限缓存

最易被忽略的是:只读账号能执行 SELECT ... FOR UPDATE 吗?不能——它会触发锁机制,需 SELECT + LOCK TABLES 权限,而只读账号没后者,直接报 ERROR 1142。但这不代表绝对安全:如果用户有 EXECUTE 权限或能访问 SQL SECURITY DEFINER 视图,仍可能间接触发写行为。

相关文章

精彩推荐