MySQL只读用户只需授予SELECT权限,必要时加SHOW CREATE TABLE或PROCESS(慎用),严禁GRANT SELECT ON .,须限定库、主机并验证无其他权限。

只读用户必须授予哪些权限
MySQL 的只读访问不是靠一个 READ ONLY 权限实现的,而是通过显式授予有限的、不带写能力的权限组合。核心是:只给 SELECT,不给 INSERT、UPDATE、DELETE、DROP、CREATE、ALTER 等任何修改类权限。
常见错误是误加 SHOW VIEW 或 LOCK TABLES——它们虽不直接写数据,但可能暴露结构或阻塞业务,生产环境应按需开启。
-
SELECT是唯一必需的基础权限 - 如需查看表结构,额外加
SHOW CREATE TABLE(注意:不是SHOW DATABASES) - 如需执行
EXPLAIN或查看执行计划,需PROCESS权限(仅限本地调试,线上慎开) - 跨库 JOIN 查询时,目标库所有涉及的表都要单独授权
SELECT
创建最小权限只读用户的完整命令
假设数据库名为 app_db,用户名为 ro_user,密码为 'secure_ro_pass',只允许从内网 192.168.10.% 连接:
CREATE USER 'ro_user'@'192.168.10.%' IDENTIFIED BY 'secure_ro_pass'; GRANT SELECT ON app_db.* TO 'ro_user'@'192.168.10.%'; FLUSH PRIVILEGES;
关键点:
- 不要用
GRANT SELECT ON *.*—— 这会暴露系统库(如information_schema),存在信息泄露风险 - 主机名尽量具体,避免用
'%';若必须通配,请确认网络层已限制访问源 -
FLUSH PRIVILEGES在大多数情况下非必需(只要用GRANT语句就自动生效),但部分旧版本或特殊部署下建议保留
验证只读权限是否生效
用新用户登录后,执行以下检查:
- 能成功运行
SELECT COUNT(*) FROM app_db.users; - 执行
INSERT INTO app_db.users (...) VALUES (...);应报错:ERROR 1142 (42000): INSERT command denied to user - 执行
SHOW GRANTS FOR CURRENT_USER;确认返回结果中只有SELECT权限,无其他 DML/DCL 权限 - 尝试
USE mysql;后查user表——应因无权限拒绝,而非返回空结果(空结果说明有权限但没数据,是严重误配置)
应用连接池中要注意的兼容性问题
某些 ORM 或连接池(如 HikariCP、Druid)在初始化时会默认执行 SELECT 1 或 SELECT @@sql_mode 等探测语句。这些语句本身没问题,但若连接字符串中指定了 database=xxx 而该库未被授权,就会连接失败。
解决方案:
- 确保
GRANT SELECT ON中的库名与应用配置完全一致(大小写敏感取决于 OS 和.* lower_case_table_names设置) - 避免在 JDBC URL 中指定不存在或未授权的
database参数;可改用useSSL=false&serverTimezone=UTC等纯连接参数 - Spring Boot + MyBatis 场景下,
spring.sql.init.mode=never必须显式设置,否则启动时可能尝试建表
最易忽略的是:MySQL 8.0+ 默认启用 caching_sha2_password 插件,而旧版客户端可能不支持——此时即使权限正确,也会卡在认证阶段,报错类似 Public Key Retrieval is not allowed。需确认客户端驱动版本或改用 mysql_native_password 认证方式。










