Documentation Home
MySQL 8.0 参考手册  / 第 6 章 安全  / 6.2 访问控制和账户管理  /  6.2.6 访问控制,第 1 阶段:连接验证

6.2.6 访问控制,第 1 阶段:连接验证

当您尝试连接到 MySQL 服务器时,服务器会根据以下条件接受或拒绝连接:

  • 您的身份以及您是否可以通过提供适当的凭据来验证它。

  • 您的帐户是被锁定还是解锁。

服务器首先检查凭据,然后检查帐户锁定状态。任一步骤的失败都会导致服务器完全拒绝您的访问。否则,服务器接受连接,然后进入阶段 2 等待请求。

服务器使用表中的列执行身份和凭据检查user,仅当满足以下条件时才接受连接:

  • 客户端主机名和用户名与 某些表行中的HostUser列相匹配。有关管理允许和 值 user的规则,请参阅第 6.2.4 节,“指定帐户名称”HostUser

  • 客户端提供行中指定的凭据(例如,密码),如 authentication_string列所示。使用列中命名的身份验证插件解释凭据 plugin

  • 该行表示该帐户已解锁。锁定状态记录在account_locked列中,该列的值必须为'N'。可以使用 CREATE USERor ALTER USER语句设置或更改帐户锁定。

您的身份基于两条信息:

  • 您的 MySQL 用户名。

  • 您连接的客户端主机。

如果User列值不为空,则传入连接中的用户名必须完全匹配。如果该 User值为空,则匹配任何用户名。如果user与传入连接匹配的表行具有空白用户名,则该用户被认为是没有名称的匿名用户,而不是具有客户端实际指定名称的用户。这意味着在连接期间(即第 2 阶段),所有进一步的访问检查都将使用空白用户名。

authentication_string列可以为空。这不是通配符,并不意味着任何密码都匹配。这意味着用户必须在不指定密码的情况下进行连接。验证客户端的插件实现的验证方法可能使用也可能不使用 authentication_string列中的密码。在这种情况下,外部密码也可能用于对 MySQL 服务器进行身份验证。

authentication_string表列中 存储的非空密码值 user已加密。MySQL 不会将密码存储为任何人都可以看到的明文。相反,尝试连接的用户提供的密码是加密的(使用由帐户身份验证插件实现的密码散列方法)。然后在连接过程中检查密码是否正确时使用加密后的密码。这是在没有通过连接传输加密密码的情况下完成的。请参阅第 6.2.1 节,“帐户用户名和密码”

从 MySQL 的角度来看,加密后的密码才是 真正的密码,所以你不应该让任何人访问它。特别是,不要授予非管理员用户对 mysql系统数据库中表的读取权限。

下表显示了表中的 UserHost值的 各种组合如何user应用于传入连接。

User价值 Host价值 允许的连接
'fred' 'h1.example.net' fred, 连接自 h1.example.net
'' 'h1.example.net' 任何用户,从h1.example.net
'fred' '%' fred, 从任何主机连接
'' '%' 任何用户,从任何主机连接
'fred' '%.example.net' fred, 从 example.net域中的任何主机连接
'fred' 'x.example.%' fred, 连接自 x.example.net, x.example.com, x.example.edu, 等等; 这可能没用
'fred' '198.51.100.177' fred, 从具有 IP 地址的主机连接 198.51.100.177
'fred' '198.51.100.%' fred198.51.100, 从C 类子网中的任何主机连接
'fred' '198.51.100.0/255.255.255.0' 与前面的示例相同

传入连接的客户端主机名和用户名可能与 user表中的多行匹配。前面的一组示例演示了这一点:显示的多个条目与来自h1.example.netby的连接相匹配fred

当可能有多个匹配项时,服务器必须确定使用其中的哪一个。它按如下方式解决此问题:

  • 每当服务器将user表读入内存时,它都会对行进行排序。

  • 当客户端尝试连接时,服务器会按排序顺序查看行。

  • 服务器使用与客户端主机名和用户名匹配的第一行。

服务器使用排序规则,Host首先对具有最具体值的行进行排序:

  • 字面 IP 地址和主机名是最具体的。

  • 在 MySQL 8.0.23 之前,文字 IP 地址的特异性不受其是否具有网络掩码的影响,因此 198.51.100.13198.51.100.0/255.255.255.0被认为是同等特异性的。从 MySQL 8.0.23 开始,在主机部分具有 IP 地址的帐户具有以下特定顺序:

    • 主机部分作为 IP 地址的帐户:

      CREATE USER 'user_name'@'127.0.0.1';
      CREATE USER 'user_name'@'198.51.100.44';
    • 使用 CIDR 表示法将主机部分作为 IP 地址给出的帐户:

      CREATE USER 'user_name'@'192.0.2.21/8';
      CREATE USER 'user_name'@'198.51.100.44/16';
    • 主机部分作为带子网掩码的 IP 地址给出的帐户:

      CREATE USER 'user_name'@'192.0.2.0/255.255.255.0';
      CREATE USER 'user_name'@'198.51.0.0/255.255.0.0';
  • 该模式'%'表示任何主机并且最不具体。

  • 空字符串''也表示任何主机,但排在 之后'%'

非 TCP(套接字文件、命名管道和共享内存)连接被视为本地连接, localhost如果有任何此类帐户,则与主机部分匹配,localhost 否则主机部分与通配符匹配(例如,, , local%) 。 l%%

具有相同Host值的行按最具体的User值排在最前面。空白 User值表示任何用户并且最不具体,因此对于具有相同Host 值的行,非匿名用户排在匿名用户之前。

对于具有同样特定HostUser值的行,顺序是不确定的。

要查看其工作原理,假设该user 表如下所示:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

当服务器将表读入内存时,它使用刚才描述的规则对行进行排序。排序后的结果是这样的:

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-

当客户端尝试连接时,服务器会查看已排序的行并使用找到的第一个匹配项。对于来自 localhostby的连接jeffrey,表中的两行匹配:具有 HostUser'localhost'和的行'',以及具有 和 值的'%''jeffrey'。该'localhost' 行按排序顺序排在第一位,因此这是服务器使用的行。

这是另一个例子。假设该user 表如下所示:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| h1.example.net |          | ...
+----------------+----------+-

排序后的表如下所示:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| h1.example.net |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

第一行匹配来自 的任何用户的连接 h1.example.net,而第二行匹配jeffrey来自任何主机的连接。

笔记

一种常见的误解是认为,对于给定的用户名,当服务器尝试为连接查找匹配项时,首先使用明确命名该用户的所有行。这不是真的。前面的示例说明了这一点,其中来自h1.example.netby 的连接jeffrey首先匹配的不是包含'jeffrey'作为 User列值的行,而是匹配没有用户名的行。结果,jeffrey被认证为匿名用户,即使他在连接时指定了用户名。

如果您能够连接到服务器,但您的权限不是您所期望的,则您可能正在以其他帐户身份进行身份验证。要找出服务器用于对您进行身份验证的帐户,请使用该 CURRENT_USER()功能。(请参阅 第 12.16 节,“信息函数”。)它返回一个格式的值,该 格式指示匹配 表行中的和 值。假设 连接并发出以下查询: user_name@host_nameUserHostuserjeffrey

mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost     |
+----------------+

此处显示的结果表明匹配的 user表行具有空白 User列值。换句话说,服务器被jeffrey视为匿名用户。

诊断身份验证问题的另一种方法是打印出该user表并手动对其进行排序,以查看第一个匹配的位置。