MySQL8 中文参考(二十四)(2)https://developer.aliyun.com/article/1566153
8.2.4 指定账户名
MySQL 账户名由用户名和主机名组成,这使得可以为从不同主机连接的具有相同用户名的用户创建不同的账户。本节描述了账户名的语法,包括特殊值和通配符规则。
在大多数方面,账户名与 MySQL 角色名类似,但有一些差异,详见第 8.2.5 节“指定角色名”。
账户名出现在 SQL 语句中,如CREATE USER
、GRANT
和SET PASSWORD
,并遵循以下规则:
- 账户名语法为
'*
user_name*'@'*
host_name*'
。 @'*
host_name*'
部分是可选的。仅由用户名组成的账户名等同于'*
user_name*'@'%'
。例如,'me'
等同于'me'@'%'
。- 如果用户名和主机名作为未引用的标识符是合法的,则不需要加引号。如果*
user_name
字符串包含特殊字符(如空格或-
),或者host_name
*字符串包含特殊字符或通配符字符(如.
或%
),则必须使用引号。例如,在账户名'test-user'@'%.com'
中,用户名称和主机名部分都需要引号。 - 将用户名称和主机名引用为标识符或字符串,可以使用反引号进行引用。
- 如果用户名和主机名部分被引用,则必须分别引用。也就是说,写成
'me'@'localhost'
,而不是'me@localhost'
。(后者实际上等同于'me@localhost'@'%'
,尽管这种行为现在已被弃用。) - 对
CURRENT_USER
或CURRENT_USER()
函数的引用等同于直接指定当前客户端的用户名和主机名。
MySQL 使用独立列在mysql
系统数据库的授权表中存储账户名的用户名称和主机名部分:
user
表为每个账户包含一行。User
和Host
列存储用户名和主机名。该表还指示了账户具有哪些全局权限。- 其他授权表显示了账户对数据库和数据库内对象的权限。这些表有
User
和Host
列用于存储账户名。这些表中的每一行都与user
表中具有相同User
和Host
值的账户相关联。 - 对于访问检查目的,User 值的比较区分大小写。Host 值的比较不区分大小写。
有关存储在授权表中的用户名称和主机名属性的详细信息,例如最大长度,请参阅 Grant Table Scope Column Properties。
用户名和主机名具有特定的特殊值或通配符约定,如下所述。
帐户名的用户名部分要么是一个非空值,字面上匹配传入连接尝试的用户名,要么是一个空值(空字符串),匹配任何用户名。具有空用户名的帐户是匿名用户。要在 SQL 语句中指定匿名用户,请使用带引号的空用户名部分,例如''@'localhost'
。
帐户名的主机名部分可以采用多种形式,并且允许使用通配符:
- 主机值可以是主机名或 IP 地址(IPv4 或 IPv6)。名称
'localhost'
表示本地主机。IP 地址'127.0.0.1'
表示 IPv4 环回接口。IP 地址'::1'
表示 IPv6 环回接口。 - 在主机名或 IP 地址值中允许使用
%
和_
通配符字符,但自 MySQL 8.0.35 起已不推荐使用,并且可能在将来的 MySQL 版本中删除。这些字符的含义与使用LIKE
运算符执行的模式匹配操作相同。例如,主机值'%'
匹配任何主机名,而值'%.mysql.com'
匹配mysql.com
域中的任何主机。'198.51.100.%'
匹配 198.51.100 类 C 网络中的任何主机。
因为主机值中允许使用 IP 通配符值(例如,'198.51.100.%'
匹配子网上的每个主机),因此某人可能尝试利用此功能,将主机命名为198.51.100.somewhere.com
。为了阻止这种尝试,MySQL 不会对以数字和点开头的主机名进行匹配。例如,如果主机名为1.2.example.com
,其名称永远不会与帐户名的主机部分匹配。IP 通配符值只能匹配 IP 地址,而不能匹配主机名。
如果partial_revokes
为ON
,MySQL 将%
和_
视为文字字符,而不是通配符。从 MySQL 8.0.35 开始,不推荐使用这些通配符(无论此变量的值如何),您应该期望这种功能在将来的 MySQL 版本中被移除。 - 对于指定为 IPv4 地址的主机值,可以提供一个子网掩码来指示用于网络号的地址位数。子网掩码表示法不能用于 IPv6 地址。语法是
*
host_ip*/*
netmask*
。例如:
CREATE USER 'david'@'198.51.100.0/255.255.255.0';
- 这使得
david
可以从具有 IP 地址*client_ip
*的任何客户端主机连接,条件如下:
*client_ip* & *netmask* = *host_ip*
- 对于刚刚显示的
CREATE USER
语句:
*client_ip* & 255.255.255.0 = 198.51.100.0
- 满足此条件的 IP 地址范围从
198.51.100.0
到198.51.100.255
。掩码通常以设置为 1 的位开始,然后是设置为 0 的位。示例:
198.0.0.0/255.0.0.0
: 198 类 A 网络上的任何主机198.51.0.0/255.255.0.0
: 198.51 类 B 网络上的任何主机198.51.100.0/255.255.255.0
: 198.51.100 类 C 网络上的任何主机198.51.100.1
: 仅具有此特定 IP 地址的主机
- 自 MySQL 8.0.23 起,指定为 IPv4 地址的主机值可以使用 CIDR 表示法,例如
198.51.100.44/24
。
服务器通过系统 DNS 解析器返回的客户端主机名或 IP 地址的值来匹配帐户名称中的主机值。除非使用网络掩码表示帐户主机值,服务器将执行此比较作为字符串匹配,即使帐户主机值以 IP 地址形式给出。这意味着您应该以 DNS 使用的相同格式指定帐户主机值。以下是需要注意的问题示例:
- 假设本地网络上的主机具有完全限定名称
host1.example.com
。如果 DNS 返回此主机的名称查找为host1.example.com
,请在帐户主机值中使用该名称。如果 DNS 只返回host1
,请改用host1
。 - 如果 DNS 返回给定主机的 IP 地址为
198.51.100.2
,则匹配帐户主机值为198.51.100.2
,但不匹配198.051.100.2
。同样,它匹配帐户主机模式如198.51.100.%
,但不匹配198.051.100.%
。
为避免此类问题,建议检查 DNS 返回主机名和地址的格式。在 MySQL 帐户名称中使用相同格式的值。
8.2.5 指定角色名称
MySQL 角色名称指的是权限的命名集合。有关角色使用示例,请参阅第 8.2.10 节“使用角色”。
角色名称的语法和语义与帐户名称类似;请参阅第 8.2.4 节“指定帐户名称”。在授予表中存储时,它们具有与帐户名称相同的属性,这些属性在授予表作用域列属性中描述。
角色名称在以下几个方面与帐户名称不同:
- 角色名称的用户部分不能留空。因此,没有类似于“匿名用户”概念的“匿名角色”。
- 对于帐户名称,省略角色名称的主机部分将导致主机部分为
'%'
。但是,与帐户名称中的'%'
不同,在角色名称中的'%'
主机部分没有通配符属性。例如,对于作为角色名称使用的名称'me'@'%'
,主机部分('%'
)只是一个文字值;它没有“任何主机”匹配属性。 - 在角色名称的主机部分中使用的网络掩码表示法没有意义。
- 在几种情况下,帐户名称允许为
CURRENT_USER()
。角色名称不允许。
mysql.user
系统表中的一行可以同时充当帐户和角色。在这种情况下,在将名称用作角色名称的上下文中,任何特殊的用户或主机名匹配属性都不适用。例如,您不能执行以下语句,并期望它设置当前会话角色,使用所有具有用户部分为myrole
和任何主机名的角色:
SET ROLE 'myrole'@'%';
相反,该语句将会话的活动角色设置为名称为'myrole'@'%'
的角色。
因此,通常只使用用户名称部分指定角色名称,并让主机名部分隐式地为'%'
。如果您打算创建一个既可以作为角色又可以从给定主机连接的用户帐户的名称,则指定具有非'%'
主机部分的角色可能很有用。
8.2.6 访问控制,阶段 1:连接验证
当你尝试连接到 MySQL 服务器时,服务器根据以下条件接受或拒绝连接:
- 你的身份以及是否可以通过提供适当的凭证来验证。
- 你的帐户是锁定还是解锁的。
服务器首先检查凭证,然后检查帐户锁定状态。任一步骤失败都会导致服务器完全拒绝您的访问。否则,服务器接受连接,然后进入阶段 2 并等待请求。
服务器使用user
表中的列执行身份和凭证检查,仅当满足以下条件时才接受连接:
- 客户端主机名和用户名与某个
user
表行中的Host
和User
列匹配。有关允许的Host
和User
值的规则,请参见 Section 8.2.4, “Specifying Account Names”。 - 客户端提供行中指定的凭证(例如,密码),如
authentication_string
列所示。凭证使用plugin
列中命名的身份验证插件进行解释。 - 该行指示帐户未锁定。锁定状态记录在
account_locked
列中,其值必须为'N'
。可以使用CREATE USER
或ALTER USER
语句设置或更改帐户锁定。
你的身份基于两个信息:
- 你的 MySQL 用户名。
- 你连接的客户端主机。
如果User
列的值非空,则传入连接中的用户名必须完全匹配。如果User
值为空,则匹配任何用户名。如果与传入连接匹配的user
表行具有空白用户名,则该用户被视为没有名称的匿名用户,而不是客户端实际指定的用户名。这意味着在连接期间(即在阶段 2 期间)使用空白用户名进行所有进一步的访问检查。
authentication_string
列可以为空。这不是通配符,也不意味着任何密码都匹配。这意味着用户必须在不指定密码的情况下连接。验证客户端的插件实现的身份验证方法可能会或可能不会使用authentication_string
列中的密码。在这种情况下,可能还会使用外部密码来对 MySQL 服务器进行身份验证。
存储在user
表的authentication_string
列中的非空密码值已加密。MySQL 不会将密码以明文形式存储供任何人查看。相反,尝试连接的用户提供的密码会被加密(使用帐户认证插件实现的密码哈希方法)。然后,在检查密码是否正确的连接过程中使用加密密码。这样做时,加密密码永远不会通过连接传输。参见 Section 8.2.1, “Account User Names and Passwords”。
从 MySQL 服务器的角度来看,加密密码是真实密码,因此您不应该向任何人提供访问权限。特别是不要向非管理员用户提供对mysql
系统数据库中表的读取权限。
以下表格显示了user
表中各种User
和Host
值的组合如何应用于传入连接。
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.%' |
fred ,从198.51.100 类 C 子网中的任何主机连接 |
'fred' |
'198.51.100.0/255.255.255.0' |
与前一个示例相同 |
客户端主机名和用户名可能与user
表中的多行匹配。前面的示例集演示了这一点:所示的几个条目与fred
通过h1.example.net
的连接匹配。
当存在多个匹配项时,服务器必须确定使用哪个。它解决此问题如下:
- 每当服务器将
user
表读入内存时,它会对行进行排序。 - 当客户端尝试连接时,服务器按顺序查看行。
- 服务器使用与客户端主机名和用户名匹配的第一行。
服务器使用排序规则,首先按最具体的Host
值对行进行排序:
- 字面 IP 地址和主机名是最具体的。
- 在 MySQL 8.0.23 之前,字面 IP 地址的特异性不受其是否具有网络掩码的影响,因此
198.51.100.13
和198.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%
,%
)。
将'%'
视为等同于localhost
的处理在 MySQL 8.0.35 中已弃用,您应该期望这种行为在将来的 MySQL 版本中被移除。
具有相同Host
值的行按照最具体的User
值首先排序。空白的User
值表示“任何用户”,是最不具体的,因此对于具有相同Host
值的行,非匿名用户排在匿名用户之前。
对于具有同等特定Host
和User
值的行,顺序是不确定的。
要了解这是如何工作的,假设user
表如下所示:
+-----------+----------+- | Host | User | ... +-----------+----------+- | % | root | ... | % | jeffrey | ... | localhost | root | ... | localhost | | ... +-----------+----------+-
当服务器将表读入内存时,使用刚才描述的规则对行进行排序。排序后的结果如下所示:
+-----------+----------+- | Host | User | ... +-----------+----------+- | localhost | root | ... | localhost | | ... | % | jeffrey | ... | % | root | ... +-----------+----------+-
当客户端尝试连接时,服务器会浏览排序后的行,并使用找到的第一个匹配项。对于由jeffrey
从localhost
连接的连接,表中的两行匹配:具有Host
和User
值为'localhost'
和''
的行,以及具有值为'%'
和'jeffrey'
的行。'localhost'
行在排序顺序中首先出现,因此服务器使用该行。
这里是另一个例子。假设user
表如下所示:
+----------------+----------+- | Host | User | ... +----------------+----------+- | % | jeffrey | ... | h1.example.net | | ... +----------------+----------+-
排序后的表如下所示:
+----------------+----------+- | Host | User | ... +----------------+----------+- | h1.example.net | | ... | % | jeffrey | ... +----------------+----------+-
第一行匹配来自h1.example.net
的任何用户的连接,而第二行匹配来自任何主机的jeffrey
的连接。
注意
一个常见的误解是认为,对于给定的用户名,当服务器尝试找到连接匹配时,所有明确命名该用户的行都会首先使用。这是不正确的。前面的例子说明了这一点,其中来自h1.example.net
的jeffrey
的连接首先匹配的不是包含'jeffrey'
作为User
列值的行,而是没有用户名的行。结果,jeffrey
被认证为匿名用户,即使他在连接时指定了用户名。
如果您能够连接到服务器,但您的权限不符合您的期望,那么您可能正在以其他帐户进行身份验证。要找出服务器用于对您进行身份验证的帐户,请使用CURRENT_USER()
函数。 (参见第 14.15 节,“信息函数”.) 它以*
user_name*@*
host_name*
格式返回一个值,指示匹配的user
表行中的User
和Host
值。假设jeffrey
连接并发出以下查询:
mysql> SELECT CURRENT_USER(); +----------------+ | CURRENT_USER() | +----------------+ | @localhost | +----------------+
这里显示的结果表明,匹配的user
表行具有空白的User
列值。换句话说,服务器将jeffrey
视为匿名用户。
诊断身份验证问题的另一种方法是打印出user
表,并手动按照顺序排列,以查看第一个匹配是在哪里进行的。
8.2.7 访问控制,第 2 阶段:请求验证
服务器接受连接后,进入访问控制的第 2 阶段。对于通过连接发出的每个请求,服务器确定您要执行的操作,然后检查您的权限是否足够。这是授予权限表中的权限列发挥作用的地方。这些权限可以来自user
、global_grants
、db
、tables_priv
、columns_priv
或procs_priv
表。(您可能会发现参考第 8.2.3 节,“授予权限表”有所帮助,该节列出了每个授予权限表中存在的列。)
user
和global_grants
表授予全局权限。这些表中的行针对给定帐户指示适用于全局基础的帐户权限,无论默认数据库是什么。例如,如果user
表授予您DELETE
权限,您可以在服务器主机上的任何数据库中删除行。明智的做法是仅向需要这些权限的人授予user
表中的权限,例如数据库管理员。对于其他用户,将user
表中的所有权限设置为'N'
,并仅在更具体的级别(特定数据库、表、列或例程)上授予权限。还可以全局授予数据库权限,但使用部分撤销来限制它们在特定数据库上的执行(参见第 8.2.12 节,“使用部分撤销限制权限”)。
db
表授予特定数据库的权限。此表的范围列中的值可以采用以下形式:
- 空白的
User
值匹配匿名用户。非空值字面匹配;用户名称中没有通配符。 - 通配符字符
%
和_
可以在Host
和Db
列中使用。这些字符的含义与使用LIKE
运算符执行的模式匹配操作相同。如果要在授予权限时使用这两个字符,必须使用反斜杠进行转义。例如,要将下划线字符(_
)包含在数据库名称中,请在GRANT
语句中指定为\_
。 '%'
或空白的Host
值表示“任何主机”。- 空白的
Db
值或%
表示“任何数据库”。
服务器将db
表读入内存并同时对其进行排序,同时读取user
表。服务器根据Host
、Db
和User
范围列对db
表进行排序。与user
表一样,排序将最具体的值放在最前面,最不具体的值放在最后,当服务器查找匹配行时,它使用找到的第一个匹配项。
tables_priv
、columns_priv
和procs_priv
表授予特定于表、特定于列和特定于例程的权限。这些表的作用域列中的值可以采用以下形式:
- 通配符字符
%
和_
可以在Host
列中使用。这些与使用LIKE
运算符执行的模式匹配操作具有相同的含义。 - 一个
'%'
或空白的Host
值表示“任何主机”。 Db
、Table_name
、Column_name
和Routine_name
列不能包含通配符或为空。
服务器根据Host
、Db
和User
列对tables_priv
、columns_priv
和procs_priv
表进行排序。这类似于db
表的排序,但更简单,因为只有Host
列可以包含通配符。
服务器使用排序后的表来验证收到的每个请求。对于需要管理员权限的请求,如SHUTDOWN
或RELOAD
,服务器仅检查user
和global_privilege
表,因为这些是唯一指定管理员权限的表。如果这些表中的帐户行允许请求的操作,则授予访问权限;否则拒绝访问。例如,如果您想执行mysqladmin shutdown,但您的user
表行没有授予您SHUTDOWN
权限,服务器会拒绝访问,甚至不会检查db
表。(后者表中不包含Shutdown_priv
列,因此无需检查它。)
对于与数据库相关的请求(INSERT
、UPDATE
等),服务器首先检查user
表行中的用户全局权限(减去部分撤销所施加的权限限制)。如果行允许请求的操作,则授予访问权限。如果user
表中的全局权限不足,则服务器从db
表中确定用户的数据库特定权限:
- 服务器在
db
表中查找与Host
、Db
和User
列匹配的内容。 Host
和User
列与连接用户的主机名和 MySQL 用户名匹配。Db
列与用户想要访问的数据库匹配。- 如果
Host
和User
没有对应的行,则拒绝访问。
在确定由db
表行授予的特定于数据库的权限后,服务器将其添加到由user
表授予的全局权限中。如果结果允许请求的操作,则授予访问权限。否则,服务器将逐个检查tables_priv
和columns_priv
表中的用户表和列权限,将它们添加到用户的权限中,并根据结果允许或拒绝访问。对于存储过程操作,服务器使用procs_priv
表而不是tables_priv
和columns_priv
。
用布尔术语表达,关于如何计算用户权限的前述描述可以总结如下:
global privileges OR database privileges OR table privileges OR column privileges OR routine privileges
如果发现全局权限最初不足以执行请求的操作,为什么服务器会在后来将这些权限添加到数据库、表和列权限中可能并不明显。原因在于一个请求可能需要多种类型的权限。例如,如果执行INSERT INTO ... SELECT
语句,您需要INSERT
和SELECT
权限。您的权限可能是user
表行全局授予一个权限,而db
表行专门为相关数据库授予另一个权限。在这种情况下,您具有执行请求所需的权限,但服务器无法仅从您的全局或数据库权限中判断出来。它必须根据综合权限做出访问控制决定。
8.2.8 添加账户、分配权限和删除账户
要管理 MySQL 账户,请使用为此目的而设计的 SQL 语句:
CREATE USER
和DROP USER
创建和移除账户。GRANT
和REVOKE
分配权限给账户并从账户中撤销权限。SHOW GRANTS
显示账户权限分配。
账户管理语句会导致服务器对底层授权表进行适当的修改,这些表在第 8.2.3 节,“授权表”中讨论。
注意
不鼓励直接使用诸如INSERT
、UPDATE
或DELETE
等语句直接修改授权表,并且自担风险。服务器可以忽略由于这些修改而变得畸形的行。
对于任何修改授权表的操作,服务器会检查表是否具有预期的结构,如果不是,则会产生错误。要将表更新为预期的结构,请执行 MySQL 升级过程。参见第三章,“升级 MySQL”。
创建账户的另一种选择是使用 GUI 工具 MySQL Workbench。此外,一些第三方程序提供了用于 MySQL 账户管理的功能。phpMyAdmin
就是这样一个程序。
本节讨论以下主题:
- 创建账户和授予权限
- 检查账户权限和属性
- 撤销账户权限
- 删除账户
有关本文讨论的语句的更多信息,请参阅第 15.7.1 节,“账户管理语句”。
创建账户和授予权限
以下示例展示如何使用mysql客户端程序设置新账户。这些示例假定 MySQL root
账户具有CREATE USER
权限以及授予其他账户的所有权限。
在命令行中,以 MySQL root
用户连接到服务器,并在密码提示符处输入适当的密码:
$> mysql -u root -p Enter password: *(enter root password here)*
连接到服务器后,您可以添加新账户。以下示例使用 CREATE USER
和 GRANT
语句设置四个账户(在看到 '*
password*'
时,请替换为适当的密码):
CREATE USER 'finley'@'localhost' IDENTIFIED BY '*password*'; GRANT ALL ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; CREATE USER 'finley'@'%.example.com' IDENTIFIED BY '*password*'; GRANT ALL ON *.* TO 'finley'@'%.example.com' WITH GRANT OPTION; CREATE USER 'admin'@'localhost' IDENTIFIED BY '*password*'; GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; CREATE USER 'dummy'@'localhost';
由这些语句创建的账户具有以下属性:
- 有两个用户名为
finley
的账户。两者都是具有完全全局权限可以执行任何操作的超级用户账户。'finley'@'localhost'
账户仅可在从本地主机连接时使用。'finley'@'%.example.com'
账户在主机部分使用'%'
通配符,因此可用于从example.com
域中的任何主机连接。
如果存在localhost
的匿名用户账户,则'finley'@'localhost'
账户是必需的。如果没有'finley'@'localhost'
账户,则当finley
从本地主机连接时,匿名用户账户优先,finley
将被视为匿名用户。原因是匿名用户账户的Host
列值比'finley'@'%'
账户更具体,因此在user
表排序顺序中排在前面。(有关user
表排序的信息,请参见 Section 8.2.6, “Access Control, Stage 1: Connection Verification”。) 'admin'@'localhost'
账户仅可由admin
用于从本地主机连接。它被授予全局RELOAD
和PROCESS
管理权限。这些权限使admin
用户能够执行 mysqladmin reload、mysqladmin refresh 和 mysqladmin flush-xxx
命令,以及 mysqladmin processlist。未授予访问任何数据库的权限。您可以使用GRANT
语句添加此类权限。'dummy'@'localhost'
账户没有密码(这是不安全且不推荐的)。此账户仅可用于从本地主机连接。未授予任何权限。假定您使用GRANT
语句为该账户授予特定权限。
前面的示例授予了全局级别的权限。下一个示例创建了三个账户,并在较低级别授予了访问权限;即,对特定数据库或数据库中的对象。每个账户的用户名都是custom
,但主机名部分不同:
CREATE USER 'custom'@'localhost' IDENTIFIED BY '*password*'; GRANT ALL ON bankaccount.* TO 'custom'@'localhost'; CREATE USER 'custom'@'host47.example.com' IDENTIFIED BY '*password*'; GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON expenses.* TO 'custom'@'host47.example.com'; CREATE USER 'custom'@'%.example.com' IDENTIFIED BY '*password*'; GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON customer.addresses TO 'custom'@'%.example.com';
这三个账户可以如下使用:
'custom'@'localhost'
账户具有访问bankaccount
数据库的所有数据库级别权限。该账户只能从本地主机连接到服务器。'custom'@'host47.example.com'
账户具有特定数据库级别权限,可以访问expenses
数据库。该账户只能从主机host47.example.com
连接到服务器。'custom'@'%.example.com'
账户具有特定表级别权限,可以访问customer
数据库中的addresses
表,来自example.com
域中的任何主机。由于在账户名的主机部分使用了%
通配符字符,该账户可以从该域中的所有机器连接到服务器。
检查账户权限和属性
要查看账户的权限,请使用SHOW GRANTS
:
mysql> SHOW GRANTS FOR 'admin'@'localhost'; +-----------------------------------------------------+ | Grants for admin@localhost | +-----------------------------------------------------+ | GRANT RELOAD, PROCESS ON *.* TO `admin`@`localhost` | +-----------------------------------------------------+
要查看账户的非权限属性,请使用SHOW CREATE USER
:
mysql> SET print_identified_with_as_hex = ON; mysql> SHOW CREATE USER 'admin'@'localhost'\G *************************** 1\. row *************************** CREATE USER for admin@localhost: CREATE USER `admin`@`localhost` IDENTIFIED WITH 'caching_sha2_password' AS 0x24412430303524301D0E17054E2241362B1419313C3E44326F294133734B30792F436E77764270373039612E32445250786D43594F45354532324B6169794F47457852796E32 REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK PASSWORD HISTORY DEFAULT PASSWORD REUSE INTERVAL DEFAULT PASSWORD REQUIRE CURRENT DEFAULT
启用print_identified_with_as_hex
系统变量(自 MySQL 8.0.17 起可用)会导致SHOW CREATE USER
显示包含不可打印字符的哈希值为十六进制字符串,而不是常规字符串文字。
撤销账户权限
要撤销账户权限,请使用REVOKE
语句。权限可以在不同级别撤销,就像它们可以在不同级别授予一样。
撤销全局权限:
REVOKE ALL ON *.* FROM 'finley'@'%.example.com'; REVOKE RELOAD ON *.* FROM 'admin'@'localhost';
撤销数据库级别权限:
REVOKE CREATE,DROP ON expenses.* FROM 'custom'@'host47.example.com';
撤销表级别权限:
REVOKE INSERT,UPDATE,DELETE ON customer.addresses FROM 'custom'@'%.example.com';
要检查权限撤销的效果,请使用SHOW GRANTS
:
mysql> SHOW GRANTS FOR 'admin'@'localhost'; +---------------------------------------------+ | Grants for admin@localhost | +---------------------------------------------+ | GRANT PROCESS ON *.* TO `admin`@`localhost` | +---------------------------------------------+
删除账户
要移除一个账户,请使用DROP USER
语句。例如,要删除之前创建的一些账户:
DROP USER 'finley'@'localhost'; DROP USER 'finley'@'%.example.com'; DROP USER 'admin'@'localhost'; DROP USER 'dummy'@'localhost';
MySQL8 中文参考(二十四)(4)https://developer.aliyun.com/article/1566158