CREATE USER语句必须显式指定host,否则创建的用户为'username'@'%',与后续GRANT中指定的'username'@'host'不匹配导致权限失效;本地连接应写为'username'@'localhost',生产环境须限制IP段如'192.168.1.%',避免使用'%',且库名含特殊字符时必须用反引号包裹。

CREATE USER 语句必须指定 host,否则权限不生效
MySQL 用户名不是孤立的字符串,而是 'username'@'host' 的组合。漏写 @'host' 或写成 'username'(没带 host)会导致后续 GRANT 失败或权限无法匹配——比如你用 CREATE USER 'reporter',实际创建的是 'reporter'@'%',但如果你后续执行 GRANT SELECT ON `sales_db`.* TO 'reporter'@'192.168.1.%',这两者根本不是同一个用户,权限不会生效。
常见错误现象:Access denied for user 'reporter'@'192.168.1.5',即使你确信授过权,大概率是 CREATE USER 和 GRANT 用的 host 不一致。
- 本地连接用
'reporter'@'localhost' - 固定内网段用
'reporter'@'192.168.1.%'(注意点号要转义,% 是通配符) - 生产环境避免用
'reporter'@'%',除非有严格网络隔离 - host 部分区分大小写,
'localhost'和'LOCALHOST'是两个不同用户
GRANT SELECT ON database_name.* 是最小可行授权,别碰 *.*
只读账号的核心就是只给 SELECT,且范围必须精确到库。用 GRANT SELECT ON `sales_db`.* TO 'reporter'@'192.168.1.%' 是标准做法;反引号包裹库名不是可选——如果库名含横线、数字开头或关键字(如 order),不加反引号会报错 ERROR 1064 (42000)。
绝对不要用 GRANT SELECT ON *.*,哪怕测试环境也不建议。它会让用户看到所有库名(包括 mysql、information_schema),可能暴露结构信息,也违背最小权限原则。
- 多个库需逐条授权:
GRANT SELECT ON `reports_db`.* TO ...和GRANT SELECT ON `analytics_db`.* TO ... - 想限制到单表?用
GRANT SELECT ON `sales_db`.`orders` TO ... - 授权后必须执行
FLUSH PRIVILEGES,否则新权限不加载(尤其在旧版本或某些容器环境中)
登录后看不到其他数据库,是预期行为,不是配置失败
MySQL 的“只能看到指定库”不是靠隐藏实现的,而是权限控制的结果。当你用只读用户登录后执行 SHOW DATABASES,它只会列出你有至少一个权限(哪怕是 USAGE)的库。而 SELECT 权限自动赋予对目标库的 USAGE,所以 sales_db 会出现,其他库不会——这是正常表现,不是 bug。
验证是否真受限:尝试 USE other_db 或 SELECT * FROM other_db.table1,会直接报错 ERROR 1044 (42000): Access denied for database。
- Navicat / DBeaver 等 GUI 工具默认只显示你能访问的库,界面看起来“干净”,但本质是服务端返回的权限列表
- 如果用户能列出所有库名,说明你误授了
SHOW DATABASES权限(该权限独立于SELECT) - MySQL 8.0+ 中,
INFORMATION_SCHEMA默认对所有用户可见,但查不到其他库的表结构,除非有对应权限
密码强度和连接限制是容易被跳过的安全细节
创建只读用户时,很多人只关注权限,却忽略账户本身的安全基线。弱密码 + 宽泛 host(如 @'%')等于把锁打开一条缝。
- 密码必须含大小写字母、数字、特殊字符,长度 ≥12;MySQL 8.0 默认启用
validate_password插件,弱密码会被拒绝 - host 尽量具体:用
'reporter'@'10.0.2.0/24'(MySQL 8.0.20+ 支持 CIDR)比'reporter'@'%'更可控 - 避免复用已有账号:为报表、BI、监控等不同用途建独立用户,方便后续审计或回收
- 定期检查:
SELECT User, Host, authentication_string FROM mysql.user WHERE User = 'reporter';确认密码哈希和 host 是否符合预期
真正麻烦的不是建用户,而是某天发现这个只读账号能连上生产库却没设 IP 限制,或者密码是 123456 还挂在 Git 历史里。权限粒度可以调,账户基础一旦松动,补救成本远高于初始化多花两分钟。


















