MySQL8 中文参考(六十四)
15.6.7.7 MySQL 诊断区
SQL 语句生成填充诊断区的诊断信息。标准 SQL 具有诊断区堆栈,每个嵌套执行上下文都包含一个诊断区。标准 SQL 还支持GET STACKED DIAGNOSTICS语法,用于在条件处理程序执行期间引用第二个诊断区。
以下讨论描述了 MySQL 中诊断区的结构,MySQL 识别的信息项,语句如何清除和设置诊断区,以及诊断区如何推送到堆栈并从堆栈中弹出。
-
诊断区结构
-
诊断区信息项
-
诊断区如何清除和填充
-
诊断区堆栈的工作原理
-
与诊断区相关的系统变量
诊断区结构
诊断区包含两种信息:
-
语句信息,例如发生的条件数量或受影响行数。
-
条件信息,例如错误代码和消息。如果语句引发多个条件,则诊断区的此部分为每个条件区域都有一个条件区域。如果语句未引发任何条件,则诊断区的此部分为空。
对于生成三个条件的语句,诊断区包含如下语句和条件信息:
Statement information:
row count
... other statement information items ...
Condition area list:
Condition area 1:
error code for condition 1
error message for condition 1
... other condition information items ...
Condition area 2:
error code for condition 2:
error message for condition 2
... other condition information items ...
Condition area 3:
error code for condition 3
error message for condition 3
... other condition information items ...
诊断区信息项
诊断区包含语句和条件信息项。数值项为整数。字符项的字符集为 UTF-8。没有任何项可以是NULL。如果语句未设置填充诊断区的语句或条件项,则其值为 0 或空字符串,取决于项的数据类型。
诊断区的语句信息部分包含以下内容:
-
NUMBER: 一个整数,表示具有信息的条件区域数量。 -
ROW_COUNT: 一个整数,表示语句影响的行数。ROW_COUNT与ROW_COUNT()函数的值相同(参见第 14.15 节,“信息函数”)。
诊断区域的条件信息部分包含每个条件的条件区域。条件区域从 1 到NUMBER语句条件项的值编号。如果NUMBER为 0,则没有条件区域。
每个条件区域包含以下列表中的项目。所有项目都是标准 SQL,除了MYSQL_ERRNO,它是 MySQL 的扩展。这些定义适用于除信号(即由SIGNAL或RESIGNAL语句生成的条件之外的条件。对于非信号条件,MySQL 仅填充未描述为始终为空的那些条件项。信号对条件区域的影响稍后描述。
-
CLASS_ORIGIN:包含RETURNED_SQLSTATE值的类的字符串。如果RETURNED_SQLSTATE值以 SQL 标准文档 ISO 9075-2(第 24.1 节,SQLSTATE)中定义的类值开头,则CLASS_ORIGIN为'ISO 9075'。否则,CLASS_ORIGIN为'MySQL'。 -
SUBCLASS_ORIGIN:包含RETURNED_SQLSTATE值的子类的字符串。如果CLASS_ORIGIN为'ISO 9075'或RETURNED_SQLSTATE以'000'结尾,则SUBCLASS_ORIGIN为'ISO 9075'。否则,SUBCLASS_ORIGIN为'MySQL'。 -
RETURNED_SQLSTATE:指示条件的SQLSTATE值的字符串。 -
MESSAGE_TEXT:指示条件的错误消息的字符串。 -
MYSQL_ERRNO:指示条件的 MySQL 错误代码的整数。 -
CONSTRAINT_CATALOG、CONSTRAINT_SCHEMA、CONSTRAINT_NAME:指示违反约束的目录、模式和名称的字符串。它们始终为空。 -
CATALOG_NAME、SCHEMA_NAME、TABLE_NAME、COLUMN_NAME:指示与条件相关的目录、模式、表和列的字符串。它们始终为空。 -
CURSOR_NAME:指示游标名称的字符串。这始终为空。
有关特定错误的RETURNED_SQLSTATE、MESSAGE_TEXT和MYSQL_ERRNO值,请参阅服务器错误消息参考。
如果SIGNAL(或RESIGNAL)语句填充诊断区域,则其SET子句可以为除RETURNED_SQLSTATE之外的任何条件信息项分配合法的数据类型值。SIGNAL还设置RETURNED_SQLSTATE值,但不是直接在其SET子句中。该值来自SIGNAL语句的SQLSTATE参数。
SIGNAL还设置语句信息项。它将NUMBER设置为 1。对于错误,它将ROW_COUNT设置为−1,否则为 0。
诊断区域如何清除和填充
非诊断性 SQL 语句会自动填充诊断区域,并且其内容可以通过SIGNAL和RESIGNAL语句明确设置。可以使用GET DIAGNOSTICS提取特定项来检查诊断区域,或者使用SHOW WARNINGS或SHOW ERRORS来查看条件或错误。
SQL 语句如下清除和设置诊断区域:
-
当服务器开始执行解析后的语句时,它会清除非诊断性语句的诊断区域。诊断性语句不会清除诊断区域。这些语句是诊断性的:
-
GET DIAGNOSTICS -
SHOW ERRORS -
SHOW WARNINGS
-
-
如果一个语句引发条件,那么诊断区域将清除属于先前语句的条件。唯一的例外是由
GET DIAGNOSTICS和RESIGNAL引发的条件会被添加到诊断区域而不清除它。
因此,即使一个语句在开始执行时通常不清除诊断区域,但如果该语句引发条件,则会清除它。
以下示例展示了各种语句对诊断区域的影响,使用SHOW WARNINGS显示存储在其中的条件信息。
这个DROP TABLE语句在条件发生时清除诊断区域并填充它:
mysql> DROP TABLE IF EXISTS test.no_such_table;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> SHOW WARNINGS;
+-------+------+------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------+
| Note | 1051 | Unknown table 'test.no_such_table' |
+-------+------+------------------------------------+
1 row in set (0.00 sec)
这个SET语句生成一个错误,因此它会清除并填充诊断区域:
mysql> SET @x = @@x;
ERROR 1193 (HY000): Unknown system variable 'x'
mysql> SHOW WARNINGS;
+-------+------+-----------------------------+
| Level | Code | Message |
+-------+------+-----------------------------+
| Error | 1193 | Unknown system variable 'x' |
+-------+------+-----------------------------+
1 row in set (0.00 sec)
先前的SET语句产生了一个条件,因此在这一点上,1 是唯一有效的GET DIAGNOSTICS条件号。以下语句使用条件号为 2,这会产生一个警告,该警告被添加到诊断区域而不清除它:
mysql> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+-------+------+------------------------------+
| Level | Code | Message |
+-------+------+------------------------------+
| Error | 1193 | Unknown system variable 'xx' |
| Error | 1753 | Invalid condition number |
+-------+------+------------------------------+
2 rows in set (0.00 sec)
现在诊断区域中有两个条件,因此相同的GET DIAGNOSTICS语句成功执行:
mysql> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @p;
+--------------------------+
| @p |
+--------------------------+
| Invalid condition number |
+--------------------------+
1 row in set (0.01 sec)
诊断区域栈的工作原理
当诊断区域栈发生推送时,第一个(当前的)诊断区域变为第二个(堆叠的)诊断区域,并创建一个新的当前诊断区域作为其副本。诊断区域在以下情况下被推送到栈中并从栈中弹出:
-
执行存储程序
程序执行前发生推送,执行后发生弹出。如果存储程序在处理程序执行时结束,则可能有多个要弹出的诊断区;这是由于没有适当处理程序的异常或处理程序中的
返回引起的。弹出的诊断区中的任何警告或错误条件都会添加到当前诊断区中,但对于触发器,只会添加错误。当存储程序结束时,调用者会在其当前诊断区中看到这些条件。
-
在存储程序中执行条件处理程序
当由于条件处理程序激活而发生推送时,堆栈诊断区是在推送之前存储程序中的当前区域。新的当前诊断区现在是处理程序的当前诊断区。
获取[当前]诊断和获取堆叠诊断可以在处理程序中使用,以访问当前(处理程序)和堆叠(存储程序)诊断区的内容。最初,它们返回相同的结果,但在处理程序中执行的语句会修改当前诊断区,根据正常规则清除和设置其内容(参见诊断区如何清除和填充)。堆叠诊断区不能被处理程序中执行的语句修改,除非使用重新发出。如果处理程序成功执行,则当前(处理程序)诊断区将被弹出,堆叠(存储程序)诊断区再次成为当前诊断区。在处理程序执行期间添加到处理程序诊断区的条件将被添加到当前诊断区。
-
执行
重新发出重新发出语句传递在存储程序内部复合语句中执行条件处理程序期间可用的错误条件信息。重新发出可能在传递之前更改一些或所有信息,根据第 15.6.7.4 节,“重新发出语句”中描述的方式修改诊断堆栈。
与诊断区相关的系统变量
某些系统变量控制或与诊断区的某些方面相关:
-
max_error_count控制诊断区域中条件区域的数量。如果发生的条件超过这个数量,MySQL 会悄悄地丢弃多余条件的信息。(通过RESIGNAL添加的条件始终会被添加,旧条件会根据需要被丢弃以腾出空间。) -
warning_count表示发生的条件数量。这包括错误、警告和注释。通常情况下,NUMBER和warning_count是相同的。然而,当生成的条件数量超过max_error_count时,warning_count的值会继续上升,而NUMBER保持在max_error_count上限,因为诊断区域中不会存储额外的条件。 -
error_count表示发生的错误数量。这个值包括“未找到”和异常条件,但不包括警告和注释。与warning_count类似,它的值可以超过max_error_count。 -
如果
sql_notes系统变量设置为 0,则不会存储注释,也不会增加warning_count。
例如:如果 max_error_count 是 10,诊断区域最多可以包含 10 个条件区域。假设一条语句引发了 20 个条件,其中有 12 个错误。在这种情况下,诊断区域包含前 10 个条件,NUMBER 是 10,warning_count 是 20,error_count 是 12。
对 max_error_count 的更改在下一次尝试修改诊断区域时才会生效。如果诊断区域包含 10 个条件区域,而 max_error_count 设置为 5,这对诊断区域的大小或内容没有立即影响。
原文:
dev.mysql.com/doc/refman/8.0/en/conditions-and-parameters.html
15.6.7.8 条件处理和 OUT 或 INOUT 参数
如果存储过程以未处理的异常退出,则OUT和INOUT参数的修改值不会传播回调用者。
如果异常由包含RESIGNAL语句的CONTINUE或EXIT处理程序处理,RESIGNAL语句的执行会弹出诊断区域栈,从而发出异常信号(即,在进入处理程序之前存在的信息)。如果异常是错误,则OUT和INOUT参数的值不会传播回调用者。
15.6.8 条件处理的限制
原文:
dev.mysql.com/doc/refman/8.0/en/condition-handling-restrictions.html
SIGNAL,RESIGNAL和GET DIAGNOSTICS不能作为预处理语句。例如,以下语句是无效的:
PREPARE stmt1 FROM 'SIGNAL SQLSTATE "02000"';
在类'04'中的SQLSTATE值不会被特殊处理。它们与其他异常一样处理。
在标准 SQL 中,第一个条件与前一个 SQL 语句返回的SQLSTATE值相关。在 MySQL 中,这并不保证,所以要获取主要错误,你不能这样做:
GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;
相反,应该这样做:
GET DIAGNOSTICS @cno = NUMBER;
GET DIAGNOSTICS CONDITION @cno @errno = MYSQL_ERRNO;
15.7 数据库管理语句
原文:
dev.mysql.com/doc/refman/8.0/en/sql-server-administration-statements.html
15.7.1 账户管理语句
15.7.2 资源组管理语句
15.7.3 表维护语句
15.7.4 组件、插件和可加载函数语句
15.7.5 CLONE 语句
15.7.6 SET 语句
15.7.7 SHOW 语句
15.7.8 其他管理语句
15.7.1 账户管理语句
原文:
dev.mysql.com/doc/refman/8.0/en/account-management-statements.html
15.7.1.1 修改用户语句
15.7.1.2 创建角色语句
15.7.1.3 创建用户语句
15.7.1.4 删除角色语句
15.7.1.5 删除用户语句
15.7.1.6 授权语句
15.7.1.7 重命名用户语句
15.7.1.8 撤销语句
15.7.1.9 设置默认角色语句
15.7.1.10 设置密码语句
15.7.1.11 设置角色语句
MySQL 账户信息存储在mysql系统模式的表中。这个数据库和访问控制系统在第七章,MySQL 服务器管理中有详细讨论,您应该查阅以获取更多细节。
重要
一些 MySQL 版本对授权表进行更改以添加新的权限或功能。为了确保您能够利用任何新功能,每次升级 MySQL 时都要将授权表更新到当前结构。请参阅第三章,升级 MySQL。
当read_only系统变量启用时,账户管理语句需要CONNECTION_ADMIN权限(或已弃用的SUPER权限),除了其他所需权限。这是因为它们修改了mysql系统模式中的表。
账户管理语句是原子性的并且具有崩溃安全性。更多信息请参见第 15.1.1 节,“原子数据定义语句支持”。
15.7.1.1 ALTER USER Statement
ALTER USER [IF EXISTS]
*user* [*auth_option*] [, *user* [*auth_option*]] ...
[REQUIRE {NONE | *tls_option* [[AND] *tls_option*] ...}]
[WITH *resource_option* [*resource_option*] ...]
[*password_option* | *lock_option*] ...
[COMMENT '*comment_string*' | ATTRIBUTE '*json_object*']
ALTER USER [IF EXISTS]
USER() *user_func_auth_option*
ALTER USER [IF EXISTS]
*user* [*registration_option*]
ALTER USER [IF EXISTS]
USER() [*registration_option*]
ALTER USER [IF EXISTS]
*user* DEFAULT ROLE
{NONE | ALL | *role* [, *role* ] ...}
*user*:
(see Section 8.2.4, “Specifying Account Names”)
*auth_option*: {
IDENTIFIED BY '*auth_string*'
[REPLACE '*current_auth_string*']
[RETAIN CURRENT PASSWORD]
| IDENTIFIED BY RANDOM PASSWORD
[REPLACE '*current_auth_string*']
[RETAIN CURRENT PASSWORD]
| IDENTIFIED WITH *auth_plugin*
| IDENTIFIED WITH *auth_plugin* BY '*auth_string*'
[REPLACE '*current_auth_string*']
[RETAIN CURRENT PASSWORD]
| IDENTIFIED WITH *auth_plugin* BY RANDOM PASSWORD
[REPLACE '*current_auth_string*']
[RETAIN CURRENT PASSWORD]
| IDENTIFIED WITH *auth_plugin* AS '*auth_string*'
| DISCARD OLD PASSWORD
| ADD *factor* *factor_auth_option* [ADD *factor* *factor_auth_option*]
| MODIFY *factor* *factor_auth_option* [MODIFY *factor* *factor_auth_option*]
| DROP *factor* [DROP *factor*]
}
*user_func_auth_option*: {
IDENTIFIED BY '*auth_string*'
[REPLACE '*current_auth_string*']
[RETAIN CURRENT PASSWORD]
| DISCARD OLD PASSWORD
}
*factor_auth_option*: {
IDENTIFIED BY '*auth_string*'
| IDENTIFIED BY RANDOM PASSWORD
| IDENTIFIED WITH *auth_plugin* BY '*auth_string*'
| IDENTIFIED WITH *auth_plugin* BY RANDOM PASSWORD
| IDENTIFIED WITH *auth_plugin* AS '*auth_string*'
}
*registration_option*: {
*factor* INITIATE REGISTRATION
| *factor* FINISH REGISTRATION SET CHALLENGE_RESPONSE AS '*auth_string*'
| *factor* UNREGISTER
}
*factor*: {2 | 3} FACTOR
*tls_option*: {
SSL
| X509
| CIPHER '*cipher*'
| ISSUER '*issuer*'
| SUBJECT '*subject*'
}
*resource_option*: {
MAX_QUERIES_PER_HOUR *count*
| MAX_UPDATES_PER_HOUR *count*
| MAX_CONNECTIONS_PER_HOUR *count*
| MAX_USER_CONNECTIONS *count*
}
*password_option*: {
PASSWORD EXPIRE [DEFAULT | NEVER | INTERVAL *N* DAY]
| PASSWORD HISTORY {DEFAULT | *N*}
| PASSWORD REUSE INTERVAL {DEFAULT | *N* DAY}
| PASSWORD REQUIRE CURRENT [DEFAULT | OPTIONAL]
| FAILED_LOGIN_ATTEMPTS *N*
| PASSWORD_LOCK_TIME {*N* | UNBOUNDED}
}
*lock_option*: {
ACCOUNT LOCK
| ACCOUNT UNLOCK
}
ALTER USER语句修改 MySQL 账户。它允许对现有账户进行身份验证、角色、SSL/TLS、资源限制、密码管理、注释和属性属性的修改。它还可以用于锁定和解锁账户。
在大多数情况下,ALTER USER需要全局CREATE USER权限,或者mysql系统模式的UPDATE权限。例外情况包括:
-
任何使用非匿名账户连接到服务器的客户端都可以更改该账户的密码。(特别是,您可以更改自己的密码。)要查看服务器对您进行身份验证的账户,请调用
CURRENT_USER()函数:SELECT CURRENT_USER(); -
对于
DEFAULT ROLE语法,ALTER USER需要这些权限:-
为另一个用户设置默认角色需要全局
CREATE USER权限,或者mysql.default_roles系统表的UPDATE权限。 -
为自己设置默认角色不需要特殊权限,只要您想要的默认角色已经授予您。
-
-
修改次要密码的语句需要这些权限:
-
使用
RETAIN CURRENT PASSWORD或DISCARD OLD PASSWORD子句需要APPLICATION_PASSWORD_ADMIN权限,用于适用于您自己账户的ALTER USER语句。该权限用于操作您自己的次要密码,因为大多数用户只需要一个密码。 -
如果要允许一个账户操作所有账户的次要密码,则需要
CREATE USER权限,而不是APPLICATION_PASSWORD_ADMIN。
-
当启用read_only系统变量时,ALTER USER还需要CONNECTION_ADMIN权限(或已弃用的SUPER权限)。
从 MySQL 8.0.27 开始,这些额外的权限考虑因素适用:
-
authentication_policy系统变量对ALTER USER语句中与身份验证相关的子句的使用施加了一定的约束;有关详细信息,请参阅该变量的描述。如果具有AUTHENTICATION_POLICY_ADMIN权限,则不适用这些约束。 -
要修改使用无密码身份验证的帐户,必须具有
PASSWORDLESS_USER_ADMIN权限。
默认情况下,如果尝试修改不存在的用户,则会发生错误。如果提供了IF EXISTS子句,则该语句会对每个不存在的命名用户产生警告,而不是错误。
重要提示
在某些情况下,ALTER USER可能会记录在服务器日志中或客户端的历史文件中,例如~/.mysql_history,这意味着明文密码可能会被任何具有读取权限的人读取。有关服务器日志中发生这种情况的条件以及如何控制它的信息,请参阅第 8.1.2.3 节,“密码和日志记录”。有关客户端日志记录的类似信息,请参阅第 6.5.1.3 节,“mysql 客户端日志记录”。
ALTER USER语句有几个方面,分别在以下主题下描述:
-
修改用户概述
-
修改用户身份验证选项
-
修改用户多因素身份验证选项
-
修改用户注册选项
-
修改用户角色选项
-
修改用户 SSL/TLS 选项
-
修改用户资源限制选项
-
修改用户密码管理选项
-
修改用户注释和属性选项
-
修改用户账户锁定选项
-
修改用户二进制日志记录
修改用户概述
对于每个受影响的帐户,ALTER USER修改mysql.user系统表中对应行,以反映语句中指定的属性。未指定的属性保留其当前值。
每个帐户名称使用第 8.2.4 节“指定帐户名称”中描述的格式。如果省略帐户名称的主机名部分,默认为'%'。还可以指定CURRENT_USER或CURRENT_USER()来引用与当前会话关联的帐户。
仅在一个情况下,可以使用USER()函数指定帐户:
ALTER USER USER() IDENTIFIED BY '*auth_string*';
这种语法使您可以在不明确命名您的帐户的情况下更改自己的密码。(该语法还支持 ALTER USER 身份验证选项中描述的REPLACE、RETAIN CURRENT PASSWORD和DISCARD OLD PASSWORD子句。)
对于允许*auth_option值跟随user值的ALTER USER语法,auth_option通过指定帐户身份验证插件、凭据(例如密码)或两者来指示帐户如何进行身份验证。每个auth_option*值仅适用于紧随其前的帐户。
根据*user规范,该语句可能包括 SSL/TLS、资源限制、密码管理和锁定属性的选项。所有这些选项都是语句的全局选项,并适用于语句中命名的所有*帐户。
示例:更改帐户的密码并将其过期。结果是,用户必须使用指定的密码连接,并在下次连接时选择一个新密码:
ALTER USER 'jeffrey'@'localhost'
IDENTIFIED BY '*new_password*' PASSWORD EXPIRE;
示例:修改帐户以使用caching_sha2_password身份验证插件和给定密码。要求每 180 天选择一个新密码,并启用失败登录跟踪,以便连续三次输入错误密码导致临时锁定帐户两天:
ALTER USER 'jeffrey'@'localhost'
IDENTIFIED WITH caching_sha2_password BY '*new_password*'
PASSWORD EXPIRE INTERVAL 180 DAY
FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 2;
示例:锁定或解锁帐户:
ALTER USER 'jeffrey'@'localhost' ACCOUNT LOCK;
ALTER USER 'jeffrey'@'localhost' ACCOUNT UNLOCK;
示例:要求帐户使用 SSL 连接,并在每小时建立 20 个连接的限制:
ALTER USER 'jeffrey'@'localhost'
REQUIRE SSL WITH MAX_CONNECTIONS_PER_HOUR 20;
示例:更改多个帐户,指定一些每个帐户的属性和一些全局属性:
ALTER USER
'jeffrey'@'localhost'
IDENTIFIED BY '*jeffrey_new_password*',
'jeanne'@'localhost',
'josh'@'localhost'
IDENTIFIED BY '*josh_new_password*'
REPLACE '*josh_current_password*'
RETAIN CURRENT PASSWORD
REQUIRE SSL WITH MAX_USER_CONNECTIONS 2
PASSWORD HISTORY 5;
jeffrey后面的IDENTIFIED BY值仅适用于其紧接的帐户,因此它仅为jeffrey更改密码为'*jeffrey_new_password*'。对于jeanne,没有每个帐户的值(因此密码保持不变)。对于josh,IDENTIFIED BY建立了一个新密码('*josh_new_password*'),指定REPLACE以验证发出ALTER USER语句的用户知道当前密码('*josh_current_password*'),并且当前密码也保留为帐户的次要密码。(因此,josh可以使用主密码或次要密码连接。)
剩余属性全局适用于语句中命名的所有帐户,因此对于两个帐户:
-
连接需要使用 SSL。
-
该帐户最多可用于两个同时连接。
-
密码更改不能重复使用最近的五个密码。
示例:丢弃josh的次要密码,只留下主密码:
ALTER USER 'josh'@'localhost' DISCARD OLD PASSWORD;
在缺少特定类型选项的情况下,帐户在这方面保持不变。例如,没有锁定选项,帐户的锁定状态不会改变。
ALTER USER 认证选项
一个帐户名后面可以跟着一个*auth_option*认证选项,指定帐户认证插件、凭据,或两者兼有。它还可以包括一个密码验证子句,指定要替换的帐户当前密码,并管理帐户是否有次要密码。
注意
仅适用于使用将凭据存储在 MySQL 内部的认证插件的帐户的随机密码生成、密码验证和次要密码子句。对于使用针对 MySQL 外部凭据系统执行身份验证的插件的帐户,密码管理也必须在该系统外部处理。有关内部凭据存储的更多信息,请参见第 8.2.15 节,“密码管理”。
-
*
auth_plugin*指定认证插件。插件名称可以是带引号的字符串文字,也可以是未带引号的名称。插件名称存储在mysql.user系统表的plugin列中。对于不指定认证插件的*
auth_option*语法,服务器分配默认插件,如默认认证插件中所述确定。有关每个插件的描述,请参见第 8.4.1 节,“认证插件”。 -
存储在内部的凭据存储在
mysql.user系统表中。'*auth_string*'值或RANDOM PASSWORD指定账户凭据,分别作为明文(未加密)字符串或以与账户关联的认证插件期望的格式进行哈希处理的形式:-
对于使用
BY '*auth_string*'语法的情况,该字符串是明文的,并且传递给认证插件进行可能的哈希处理。插件返回的结果存储在mysql.user表中。插件可以按照指定的值使用该值,这种情况下不会进行哈希处理。 -
对于使用
BY RANDOM PASSWORD语法的情况,MySQL 生成一个随机密码并作为明文传递给认证插件进行可能的哈希处理。插件返回的结果存储在mysql.user表中。插件可以按照指定的值使用该值,这种情况下不会进行哈希处理。随机生成的密码从 MySQL 8.0.18 开始可用,并具有 随机密码生成 中描述的特性。
-
对于使用
AS '*auth_string*'语法的情况,该字符串被假定已经是认证插件所需的格式,并且原样存储在mysql.user表中。如果插件需要哈希值,则该值必须已经以适合插件的格式进行哈希处理;否则,插件无法使用该值,也无法正确验证客户端连接。从 MySQL 8.0.17 开始,哈希字符串可以是字符串文字或十六进制值。后者对应于当启用
print_identified_with_as_hex系统变量时,包含不可打印字符的密码哈希的SHOW CREATE USER显示的值类型。 -
如果认证插件不对认证字符串进行哈希处理,则
BY '*auth_string*'和AS '*auth_string*'子句具有相同的效果:认证字符串原样存储在mysql.user系统表中。
-
-
REPLACE '*current_auth_string*'子句执行密码验证,并从 MySQL 8.0.13 开始可用。如果给出:-
REPLACE指定要替换的账户当前密码,作为明文(未加密)字符串。 -
如果账户的密码更改需要指定当前密码以验证尝试进行更改的用户实际上知道当前密码,则必须给出该子句。
-
如果账户的密码更改可能但不一定需要指定当前密码,则该子句是可选的。
-
如果给出了该子句但与当前密码不匹配,则语句将失败,即使该子句是可选的。
-
只有在更改当前用户的账户密码时才能指定
REPLACE。
有关通过指定当前密码进行密码验证的更多信息,请参见第 8.2.15 节,“密码管理”。
-
-
RETAIN CURRENT PASSWORD和DISCARD OLD PASSWORD子句实现了双密码功能,并自 MySQL 8.0.14 起可用。两者都是可选的,但如果给出,则具有以下效果:-
RETAIN CURRENT PASSWORD保留账户当前密码作为其次要密码,替换任何现有的次要密码。新密码成为主密码,但客户端可以使用账户使用主密码或次要密码连接到服务器。(例外情况:如果ALTER USER语句指定的新密码为空,则次要密码也变为空,即使给出了RETAIN CURRENT PASSWORD。) -
如果为具有空主密码的账户指定了
RETAIN CURRENT PASSWORD,则该语句将失败。 -
如果一个账户有次要密码,并且您更改其主密码而没有指定
RETAIN CURRENT PASSWORD,则次要密码保持不变。 -
如果更改分配给账户的身份验证插件,则次要密码将被丢弃。如果更改身份验证插件并且还指定了
RETAIN CURRENT PASSWORD,则该语句将失败。 -
DISCARD OLD PASSWORD丢弃次要密码(如果存在)。账户仅保留其主密码,客户端只能使用主密码连接到服务器。
有关双密码使用的更多信息,请参见第 8.2.15 节,“密码管理”。
-
ALTER USER允许这些*auth_option*语法:
-
IDENTIFIED BY '*auth_string*' [REPLACE '*current_auth_string*'] [RETAIN CURRENT PASSWORD]将账户身份验证插件设置为默认插件,将明文
'*auth_string*'值传递给插件进行可能的哈希处理,并将结果存储在mysql.user系统表中的账户行中。如果指定了
REPLACE子句,则指定了当前账户密码,如本节前文所述。如果给出了
RETAIN CURRENT PASSWORD子句,则导致保留账户当前密码作为其次要密码,如本节前文所述。 -
IDENTIFIED BY RANDOM PASSWORD [REPLACE '*current_auth_string*'] [RETAIN CURRENT PASSWORD]将账户认证插件设置为默认插件,生成一个随机密码,将明文密码值传递给插件进行可能的哈希处理,并将结果存储在
mysql.user系统表中的账户行中。该语句还会将明文密码作为结果集返回,以便用户或应用程序执行该语句时使用。有关结果集和随机生成密码特性的详细信息,请参见随机密码生成。REPLACE子句,如果给定,指定账户当前密码,如本节前文所述。RETAIN CURRENT PASSWORD子句,如果给定,会导致账户当前密码保留为其次要密码,如本节前文所述。 -
IDENTIFIED WITH *auth_plugin*将账户认证插件设置为*
auth_plugin*,将凭据清空为空字符串(凭据与旧认证插件相关联,而不是新的插件),并将结果存储在mysql.user系统表中的账户行中。此外,密码被标记为过期。用户在下次连接时必须选择新密码。
-
IDENTIFIED WITH *auth_plugin* BY '*auth_string*' [REPLACE '*current_auth_string*'] [RETAIN CURRENT PASSWORD]将账户认证插件设置为*
auth_plugin*,将明文'*auth_string*'值传递给插件进行可能的哈希处理,并将结果存储在mysql.user系统表中的账户行中。REPLACE子句,如果给定,指定账户当前密码,如本节前文所述。RETAIN CURRENT PASSWORD子句,如果给定,会导致账户当前密码保留为其次要密码,如本节前文所述。 -
IDENTIFIED WITH *auth_plugin* BY RANDOM PASSWORD [REPLACE '*current_auth_string*'] [RETAIN CURRENT PASSWORD]将账户认证插件设置为*
auth_plugin*,生成一个随机密码,将明文密码值传递给插件进行可能的哈希处理,并将结果存储在mysql.user系统表中的账户行中。该语句还会将明文密码作为结果集返回,以便用户或应用程序执行该语句时使用。有关结果集和随机生成密码特性的详细信息,请参见随机密码生成。REPLACE子句,如果给定,指定账户当前密码,如本节前文所述。RETAIN CURRENT PASSWORD子句,如果给定,会导致账户当前密码保留为其次要密码,如本节前文所述。 -
IDENTIFIED WITH *auth_plugin* AS '*auth_string*'将账户认证插件设置为*
auth_plugin*,并将'*auth_string*'值原样存储在mysql.user账户行中。如果插件需要哈希字符串,则假定字符串已经以插件所需的格式进行了哈希处理。 -
DISCARD OLD PASSWORD丢弃账户的次要密码,如果存在的话,如本节前面描述的。
示例:将密码指定为明文;使用默认插件:
ALTER USER 'jeffrey'@'localhost'
IDENTIFIED BY '*password*';
示例:指定认证插件,以及一个明文密码值:
ALTER USER 'jeffrey'@'localhost'
IDENTIFIED WITH mysql_native_password
BY '*password*';
示例:与前面的示例类似,但另外指定当前密码作为明文值,以满足用户更改时需要知道该密码的任何账户要求:
ALTER USER 'jeffrey'@'localhost'
IDENTIFIED WITH mysql_native_password
BY '*password*'
REPLACE '*current_password*';
除非当前用户是jeffrey,否则上述语句将失败,因为REPLACE仅允许更改当前用户的密码。
示例:建立一个新的主密码,并保留现有密码作为次要密码:
ALTER USER 'jeffrey'@'localhost'
IDENTIFIED BY '*new_password*'
RETAIN CURRENT PASSWORD;
示例:丢弃次要密码,仅保留账户的主密码:
ALTER USER 'jeffery'@'localhost' DISCARD OLD PASSWORD;
示例:指定认证插件,以及一个哈希密码值:
ALTER USER 'jeffrey'@'localhost'
IDENTIFIED WITH mysql_native_password
AS '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4';
有关设置密码和认证插件的更多信息,请参见第 8.2.14 节,“分配账户密码”和第 8.2.17 节,“可插拔认证”。
更改用户多因素认证选项
截至 MySQL 8.0.27,ALTER USER具有ADD、MODIFY和DROP子句,允许添加、修改或删除认证因素。在每种情况下,子句指定要对一个认证因素执行的操作,以及可选地对另一个认证因素执行的操作。对于每个操作,*factor*项指定了FACTOR关键字,前面跟着数字 2 或 3,以指示操作是应用于第二个还是第三个认证因素。(在此上下文中不允许使用 1。要对第一个认证因素执行操作,请使用 ALTER USER Authentication Options 中描述的语法。)
ALTER USER多因素认证子句的约束由authentication_policy系统变量定义。例如,authentication_policy设置控制账户可以拥有的认证因素数量,以及对于每个因素,允许使用哪些认证方法。请参阅配置多因素认证策略。
当ALTER USER在单个语句中添加、修改或删除第二个和第三个因素时,操作是按顺序执行的,但如果序列中的任何操作失败,则整个ALTER USER语句将失败。
对于ADD,每个命名因素都不得已存在,否则无法添加。对于MODIFY和DROP,每个命名因素必须存在才能被修改或删除。如果定义了第二个和第三个因素,删除第二个因素会导致第三个因素取代它成为第二个因素。
此语句删除认证因素 2 和 3,从而将帐户从 3FA 转换为 1FA:
ALTER USER '*user*' DROP 2 FACTOR 3 FACTOR;
有关其他ADD,MODIFY和DROP示例,请参阅开始使用多因素认证。
有关确定未命名插件的认证子句的默认认证插件的特定规则的信息,请参阅默认认证插件。
ALTER USER 注册选项
截至 MySQL 8.0.27,ALTER USER具有允许注册和注销 FIDO 设备的子句。有关更多信息,请参阅使用 FIDO 认证,FIDO 设备注销以及mysql客户端--fido-register-factor选项描述。
mysql客户端--fido-register-factor选项,用于 FIDO 设备注册,会导致mysql客户端生成并执行INITIATE REGISTRATION和FINISH REGISTRATION语句。这些语句不适用于手动执行。
ALTER USER 角色选项
ALTER USER ... DEFAULT ROLE定义了用户连接到服务器并进行身份验证时激活的角色,或者用户在会话期间执行SET ROLE DEFAULT语句时激活的角色。
ALTER USER ... DEFAULT ROLE 是 SET DEFAULT ROLE 的替代语法(参见 第 15.7.1.9 节,“SET DEFAULT ROLE Statement”)。然而,ALTER USER 只能为单个用户设置默认值,而 SET DEFAULT ROLE 可以为多个用户设置默认值。另一方面,您可以将 CURRENT_USER 指定为 ALTER USER 语句的用户名,而对于 SET DEFAULT ROLE 则不行。
每个用户账户名称使用先前描述的格式。
每个角色名称使用 第 8.2.5 节,“指定角色名称” 中描述的格式。例如:
ALTER USER 'joe'@'10.0.0.1' DEFAULT ROLE administrator, developer;
如果省略角色���称的主机名部分,则默认为 '%'。
在 DEFAULT ROLE 关键字后的子句允许这些值:
-
NONE:将默认设置为NONE(无角色)。 -
ALL:将默认设置为授予该账户的所有角色。 -
*role* [, *role* ] ...:将默认设置为指定的角色,这些角色必须在执行ALTER USER ... DEFAULT ROLE时存在并授予该账户。
修改用户 SSL/TLS 选项
MySQL 可以检查 X.509 证书属性,除了基于用户名和凭据的常规身份验证外。有关在 MySQL 中使用 SSL/TLS 的背景信息,请参见 第 8.3 节,“使用加密连接”。
要为 MySQL 账户指定 SSL/TLS 相关选项,请使用包含一个或多个 tls_option 值的 REQUIRE 子句。
REQUIRE 选项的顺序无关紧要,但不能指定两次选项。在 REQUIRE 选项之间的 AND 关键字是可选的。
ALTER USER 允许这些 tls_option 值:
-
NONE表明由该语句指定的所有账户没有 SSL 或 X.509 要求。如果用户名和密码有效,则允许非加密连接。如果客户端具有正确的证书和密钥文件,则客户端可以选择使用加密连接。
ALTER USER 'jeffrey'@'localhost' REQUIRE NONE;客户端默认尝试建立安全连接。对于具有
REQUIRE NONE的客户端,如果无法建立安全连接,则连接尝试会回退到非加密连接。要求加密连接,客户端只需指定--ssl-mode=REQUIRED选项;如果无法建立安全连接,则连接尝试失败。 -
SSL告诉服务器只允许通过加密连接访问由该语句指定的所有账户。
ALTER USER 'jeffrey'@'localhost' REQUIRE SSL;客户端默认尝试建立安全连接。对于具有
REQUIRE SSL的帐户,如果无法建立安全连接,则连接尝试失败。 -
X509对于所有由该语句命名的帐户,要求客户端提供有效证书,但确切的证书、颁发者和主题并不重要。唯一的要求是应该能够使用其中一个 CA 证书验证其签名。使用 X.509 证书始终意味着加密,因此在这种情况下
SSL选项是不必要的。ALTER USER 'jeffrey'@'localhost' REQUIRE X509;对于具有
REQUIRE X509的帐户,客户端必须指定--ssl-key和--ssl-cert选项进行连接。(建议但不是必须还指定--ssl-ca,以便验证服务器提供的公共证书。)对于ISSUER和SUBJECT也是如此,因为这些REQUIRE选项暗示了X509的要求。 -
颁发者 '*issuer*'对于所有由该语句命名的帐户,要求客户端提供由 CA
'*issuer*'颁发的有效 X.509 证书。如果客户端提供的证书有效但颁发者不同,服务器将拒绝连接。使用 X.509 证书始终意味着加密,因此在这种情况下SSL选项是不必要的。ALTER USER 'jeffrey'@'localhost' REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/ O=MySQL/CN=CA/emailAddress=ca@example.com';因为
ISSUER暗示了X509的要求,客户端必须指定--ssl-key和--ssl-cert选项进行连接。(建议但不是必须还指定--ssl-ca,以便验证服务器提供的公共证书。) -
主题 '*subject*'对于所有由该语句命名的帐户,要求客户端提供包含主题*
subject*的有效 X.509 证书。如果客户端提供的证书有效但主题不同,服务器将拒绝连接。使用 X.509 证书始终意味着加密,因此在这种情况下SSL选项是不必要的。ALTER USER 'jeffrey'@'localhost' REQUIRE SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/ O=MySQL demo client certificate/ CN=client/emailAddress=client@example.com';MySQL 对
'*subject*'值与证书中的值进行简单的字符串比较,因此大小写和组件顺序必须与证书中的完全相同。因为
SUBJECT暗示了X509的要求,客户端必须指定--ssl-key和--ssl-cert选项进行连接。(建议但不是必须还指定--ssl-ca,以便验证服务器提供的公共证书。) -
密码 '*cipher*'对于语句命名的所有帐户,需要特定的密码方法来加密连接。需要此选项以确保使用足够强度的密码和密钥长度的密码和密钥。如果使用旧算法和短加密密钥的算法,则加密可能较弱。
ALTER USER 'jeffrey'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA';
SUBJECT、ISSUER和CIPHER选项可以在REQUIRE子句中组合使用:
ALTER USER 'jeffrey'@'localhost'
REQUIRE SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/
O=MySQL demo client certificate/
CN=client/emailAddress=client@example.com'
AND ISSUER '/C=SE/ST=Stockholm/L=Stockholm/
O=MySQL/CN=CA/emailAddress=ca@example.com'
AND CIPHER 'EDH-RSA-DES-CBC3-SHA';
ALTER USER 资源限制选项
可以对帐户使用服务器资源的限制进行限制,如第 8.2.21 节“设置帐户资源限制”中所讨论的。为此,请使用指定一个或多个*resource_option*值的WITH子句。
WITH选项的顺序无关紧要,除非给定资源限制多次指定,否则最后一次实例优先。
ALTER USER允许使用以下*resource_option*值:
-
MAX_QUERIES_PER_HOUR *count*、MAX_UPDATES_PER_HOUR *count*、MAX_CONNECTIONS_PER_HOUR *count*对于语句命名的所有帐户,这些选项限制了在任何给定的一小时内每个帐户对服务器执行多少查询、更新和连接。如果*
count*为0(默认值),这意味着该帐户没有限制。 -
MAX_USER_CONNECTIONS *count*对于语句命名的所有帐户,限制每个帐户对服务器的最大同时连接数。非零*
count明确指定了帐户的限制。如果count*为0(默认值),服务器将根据max_user_connections系统变量的全局值确定帐户的同时连接数。如果max_user_connections也为零,则该帐户没有限制。
示例:
ALTER USER 'jeffrey'@'localhost'
WITH MAX_QUERIES_PER_HOUR 500 MAX_UPDATES_PER_HOUR 100;
ALTER USER 密码管理选项
ALTER USER支持几个*password_option*值用于密码管理:
-
密码过期选项:您可以手动使帐户密码过期并建立其密码过期策略。策略选项不会使密码过期。相反,它们确定服务器如何根据密码年龄自动使帐户密码过期,该年龄是从最近更改帐户密码的日期和时间评估的。
-
密码重用选项:您可以基于密码更改次数、经过的时间或两者限制密码重用。
-
密码验证必需选项:您可以指示更改帐户密码的尝试是否必须指定当前密码,以验证试图进行更改的用户实际上知道当前密码。
-
不正确密码的失败登录跟踪选项:您可以导致服务器跟踪失败的登录尝试,并临时锁定给出太多连续不正确密码的帐户。可配置失败次数和锁定时间。
本节描述了密码管理选项的语法。有关建立密码管理策略的信息,请参见第 8.2.15 节“密码管理”。
如果指定了给定类型的多个密码管理选项,则最后一个优先。例如,PASSWORD EXPIRE DEFAULT PASSWORD EXPIRE NEVER与PASSWORD EXPIRE NEVER相同。
注意
除了与失败登录跟踪相关的选项外,密码管理选项仅适用于使用将凭据存储在 MySQL 内部的身份验证插件的帐户。对于使用针对 MySQL 外部凭据系统执行身份验证的插件的帐户,密码管理也必须在该系统外部处理。有关内部凭据存储的更多信息,请参见第 8.2.15 节“密码管理”。
如果客户端的帐户密码已手动过期或密码年龄被认为大于其允许的生命周期,根据自动过期策略,客户端的密码已过期。在这种情况下,服务器要么断开客户端的连接,要么限制其允许的操作(请参见第 8.2.16 节“服务器处理过期密码”)。受限客户端执行的操作会导致错误,直到用户建立新的帐户密码。
注意
尽管可以通过将过期密码重置为当前值来“重置”过期密码,但作为良好政策的一部分,最好选择不同的密码。 DBA 可以通过建立适当的密码重用策略来强制执行不重用。请参见密码重用策略。
ALTER USER允许这些*password_option*值来控制密码过期:
-
PASSWORD EXPIRE立即标记由语句命名的所有帐户的密码过期。
ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE; -
PASSWORD EXPIRE DEFAULT将由语句命名的所有帐户设置为适用全局过期策略,由
default_password_lifetime系统变量指定。ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE DEFAULT; -
PASSWORD EXPIRE NEVER此过期选项覆盖了语句命名的所有帐户的全局策略。对于每个帐户,它禁用密码过期,使密码永不过期。
ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE NEVER; -
PASSWORD EXPIRE INTERVAL *N* DAY此过期选项覆盖了声明中所有命名的账户的全局策略。对于每个账户,它将密码寿命设置为*
N*天。以下声明要求每 180 天更改一次密码:ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE INTERVAL 180 DAY;
ALTER USER 允许这些*password_option*值来控制基于所需最小密码更改次数的先前密码重用:
-
PASSWORD HISTORY DEFAULT设置所有由声明命名的账户,以便全局关于密码历史长度的策略适用,以禁止在由
password_history系统变量指定的更改次数之前重用密码。ALTER USER 'jeffrey'@'localhost' PASSWORD HISTORY DEFAULT; -
PASSWORD HISTORY *N*此历史长度选项覆盖了声明中所有命名的账户的全局策略。对于每个账户,它将密码历史长度设置为*
N个密码,以禁止重新使用最近选择的N*个密码中的任何一个。以下声明禁止重新使用之前的 6 个密码:ALTER USER 'jeffrey'@'localhost' PASSWORD HISTORY 6;
ALTER USER 允许这些*password_option*值来控制基于经过的时间重新使用先前密码的情况:
-
PASSWORD REUSE INTERVAL DEFAULT设置所有由账户命名的声明,以便全局关于经过时间的策略适用,以禁止重用比由
password_reuse_interval系统变量指定的天数新的密码。ALTER USER 'jeffrey'@'localhost' PASSWORD REUSE INTERVAL DEFAULT; -
PASSWORD REUSE INTERVAL *N* DAY此经过时间选项覆盖了声明中所有命名的账户的全局策略。对于每个账户,它将密码重用间隔设置为*
N*天,以禁止重用比该天数新的密码。以下声明禁止密码在 360 天内重用:ALTER USER 'jeffrey'@'localhost' PASSWORD REUSE INTERVAL 360 DAY;
ALTER USER 允许这些*password_option*值来控制是否尝试更改账户密码必须指定当前密码,以验证尝试进行更改的用户实际上知道当前密码:
-
PASSWORD REQUIRE CURRENT此验证选项覆盖了声明中所有命名的账户的全局策略。对于每个账户,它要求密码更改必须指定当前密码。
ALTER USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT; -
PASSWORD REQUIRE CURRENT OPTIONAL此验证选项覆盖了声明中所有命名的账户的全局策略。对于每个账户,它不要求密码更改必须指定当前密码。(当前密码可以给出,但不是必须的。)
ALTER USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT OPTIONAL; -
PASSWORD REQUIRE CURRENT DEFAULT设置所有由账户命名的声明,以便全局关于密码验证的策略适用,如
password_require_current系统变量所指定的那样。ALTER USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT DEFAULT;
从 MySQL 8.0.19 开始,ALTER USER 允许使用以下 password_option 值来控制失败登录跟踪:
-
FAILED_LOGIN_ATTEMPTS *N*是否跟踪指定错误密码的账户登录尝试。
N必须是从 0 到 32767 的数字。值为 0 禁用失败登录跟踪。大于 0 的值表示多少连续密码失败会导致临时账户锁定(如果PASSWORD_LOCK_TIME也非零)。 -
PASSWORD_LOCK_TIME {*N* | UNBOUNDED}在太多连续登录尝试提供错误密码后锁定账户多长时间。
N必须是从 0 到 32767 的数字,或UNBOUNDED。值为 0 禁用临时账户锁定。大于 0 的值表示锁定账户的天数。值为UNBOUNDED导致账户锁定持续时间无限;一旦锁定,账户将保持锁定状态直到解锁。有关解锁发生的条件,请参阅 Failed-Login Tracking and Temporary Account Locking。
要实现失败登录跟踪和临时锁定,一个账户的 FAILED_LOGIN_ATTEMPTS 和 PASSWORD_LOCK_TIME 选项都必须非零。以下语句修改一个账户,使其在连续四次密码失败后保持锁定两天:
ALTER USER 'jeffrey'@'localhost'
FAILED_LOGIN_ATTEMPTS 4 PASSWORD_LOCK_TIME 2;
修改用户评论和属性选项
MySQL 8.0.21 及更高版本支持用户评论和用户属性,如 Section 15.7.1.3, “CREATE USER Statement” 中所述。这些可以通过 ALTER USER 使用 COMMENT 和 ATTRIBUTE 选项进行修改。不能在同一 ALTER USER 语句中同时指定这两个选项;尝试这样做会导致语法错误。
用户评论和用户属性存储在信息模式 USER_ATTRIBUTES 表中作为 JSON 对象;用户评论存储为此表的 ATTRIBUTE 列中 comment 键的值,如后面的讨论所示。COMMENT 文本可以是任意带引号的文本,并替换任何现有用户评论。ATTRIBUTE 值必须是 JSON 对象的有效字符串表示。这与任何现有用户属性合并,就好像在现有用户属性和新用户属性上使用了 JSON_MERGE_PATCH() 函数;对于重新使用的任何键,新值会覆盖旧值,如下所示:
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER='bill' AND HOST='localhost';
+------+-----------+----------------+
| USER | HOST | ATTRIBUTE |
+------+-----------+----------------+
| bill | localhost | {"foo": "bar"} |
+------+-----------+----------------+
1 row in set (0.11 sec)
mysql> ALTER USER 'bill'@'localhost' ATTRIBUTE '{"baz": "faz", "foo": "moo"}';
Query OK, 0 rows affected (0.22 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER='bill' AND HOST='localhost';
+------+-----------+------------------------------+
| USER | HOST | ATTRIBUTE |
+------+-----------+------------------------------+
| bill | localhost | {"baz": "faz", "foo": "moo"} |
+------+-----------+------------------------------+
1 row in set (0.00 sec)
要从用户属性中删除键及其值,将键设置为 JSON null(必须小写且不带引号),如下所示:
mysql> ALTER USER 'bill'@'localhost' ATTRIBUTE '{"foo": null}';
Query OK, 0 rows affected (0.08 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER='bill' AND HOST='localhost';
+------+-----------+----------------+
| USER | HOST | ATTRIBUTE |
+------+-----------+----------------+
| bill | localhost | {"baz": "faz"} |
+------+-----------+----------------+
1 row in set (0.00 sec)
要将现有用户的注释设置为空字符串,请使用ALTER USER ... COMMENT ''。这将在USER_ATTRIBUTES表中留下一个空的comment值;要完全删除用户注释,请使用ALTER USER ... ATTRIBUTE ...,将列键的值设置为 JSON null(小写,不带引号)。下面是一系列 SQL 语句的示例:
mysql> ALTER USER 'bill'@'localhost' COMMENT 'Something about Bill';
Query OK, 0 rows affected (0.06 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER='bill' AND HOST='localhost';
+------+-----------+---------------------------------------------------+
| USER | HOST | ATTRIBUTE |
+------+-----------+---------------------------------------------------+
| bill | localhost | {"baz": "faz", "comment": "Something about Bill"} |
+------+-----------+---------------------------------------------------+
1 row in set (0.00 sec)
mysql> ALTER USER 'bill'@'localhost' COMMENT '';
Query OK, 0 rows affected (0.09 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER='bill' AND HOST='localhost';
+------+-----------+-------------------------------+
| USER | HOST | ATTRIBUTE |
+------+-----------+-------------------------------+
| bill | localhost | {"baz": "faz", "comment": ""} |
+------+-----------+-------------------------------+
1 row in set (0.00 sec)
mysql> ALTER USER 'bill'@'localhost' ATTRIBUTE '{"comment": null}';
Query OK, 0 rows affected (0.07 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER='bill' AND HOST='localhost';
+------+-----------+----------------+
| USER | HOST | ATTRIBUTE |
+------+-----------+----------------+
| bill | localhost | {"baz": "faz"} |
+------+-----------+----------------+
1 row in set (0.00 sec)
ALTER USER 帐户锁定选项
MySQL 支持使用ACCOUNT LOCK和ACCOUNT UNLOCK选项进行帐户锁定和解锁,这些选项指定帐户的锁定状态。有关更多讨论,请参阅第 8.2.20 节,“帐户锁定”。
如果指定了多个帐户锁定选项,则最后一个优先。
ALTER USER ... ACCOUNT UNLOCK 解锁由语句指定的任何因登录失败次数过多而暂时锁定的帐户。请参阅第 8.2.15 节,“密码管理”。
ALTER USER 二进制日志记录
ALTER USER 如果成功,则写入二进制日志,但如果失败则不会;在这种情况下,将发生回滚,不会进行任何更改。写入二进制日志的语句包括所有命名用户。如果给出了IF EXISTS子句,则甚至包括那些不存在且未被更改的用户。
如果原始语句更改了用户的凭据,则写入二进制日志的语句指定了该用户的适用身份验证插件,��定如下:
-
如果原始语句中指定了插件的名称,则插件的名称。
-
否则,与用户帐户关联的插件(如果用户存在),或者默认身份验证插件(如果用户不存在)。(如果写入二进制日志的语句必须为用户指定特定的身份验证插件,请在原始语句中包含它。)
如果服务器为写入二进制日志的语句中的任何用户添加默认身份验证插件,则会向错误日志中写入警告,列出这些用户。
如果原始语句指定了FAILED_LOGIN_ATTEMPTS或PASSWORD_LOCK_TIME选项,则写入二进制日志的语句包括该选项。
具有支持多因素身份验证(MFA)的子句的ALTER USER语句被写入二进制日志,但不包括ALTER USER *user factor* INITIATE REGISTRATION语句。
-
ALTER USER *user factor* FINISH REGISTRATION SET CHALLENGE_RESPONSE AS '*auth_string*'语句被写入二进制日志为ALTER USER *user* MODIFY *factor* IDENTIFIED WITH authentication_fido AS *fido_hash_string*; -
在复制环境中,复制用户需要
PASSWORDLESS_USER_ADMIN权限来执行对使用authentication_fido插件配置为无密码身份验证的帐户进行ALTER USER ... MODIFY操作。
15.7.1.2 CREATE ROLE Statement
CREATE ROLE [IF NOT EXISTS] *role* [, *role* ] ...
CREATE ROLE 创建一个或多个角色,这些角色是命名的权限集合。要使用此语句,您必须具有全局CREATE ROLE或CREATE USER权限。当启用read_only系统变量时,CREATE ROLE 还需要CONNECTION_ADMIN权限(或已弃用的SUPER权限)。
创建角色时,角色被锁定,没有密码,并分配默认的身份验证插件。(这些角色属性可以由具有全局CREATE USER权限的用户稍后使用ALTER USER语句更改。)
CREATE ROLE 对所有命名角色要么成功,要么回滚并且不起作用,如果发生任何错误。默认情况下,如果尝试创建已经存在的角色,则会发生错误。如果给出了IF NOT EXISTS子句,则该语句对每个已经存在的命名角色产生警告,而不是错误。
如果成功,该语句将写入二进制日志,但如果失败则不会写入;在这种情况下,将发生回滚,不会进行任何更改。写入二进制日志的语句包括所有命名角色。如果给出了IF NOT EXISTS子句,则即使已经存在且未被创建的角色也会包括在内。
每个角色名称都使用第 8.2.5 节,“指定角色名称”中描述的格式。例如:
CREATE ROLE 'admin', 'developer';
CREATE ROLE 'webapp'@'localhost';
角色名称的主机名部分,如果省略,默认为'%'。
有关角色使用示例,请参见第 8.2.10 节,“使用角色”。
15.7.1.3 CREATE USER Statement
CREATE USER [IF NOT EXISTS]
*user* [*auth_option*] [, *user* [*auth_option*]] ...
DEFAULT ROLE *role* [, *role* ] ...
[REQUIRE {NONE | *tls_option* [[AND] *tls_option*] ...}]
[WITH *resource_option* [*resource_option*] ...]
[*password_option* | *lock_option*] ...
[COMMENT '*comment_string*' | ATTRIBUTE '*json_object*']
*user*:
(see Section 8.2.4, “Specifying Account Names”)
*auth_option*: {
IDENTIFIED BY '*auth_string*' [AND *2fa_auth_option*]
| IDENTIFIED BY RANDOM PASSWORD [AND *2fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* [AND *2fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* BY '*auth_string*' [AND *2fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* BY RANDOM PASSWORD [AND *2fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* AS '*auth_string*' [AND *2fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* [*initial_auth_option*]
}
*2fa_auth_option*: {
IDENTIFIED BY '*auth_string*' [AND *3fa_auth_option*]
| IDENTIFIED BY RANDOM PASSWORD [AND *3fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* [AND *3fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* BY '*auth_string*' [AND *3fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* BY RANDOM PASSWORD [AND *3fa_auth_option*]
| IDENTIFIED WITH *auth_plugin* AS '*auth_string*' [AND *3fa_auth_option*]
}
*3fa_auth_option*: {
IDENTIFIED BY '*auth_string*'
| IDENTIFIED BY RANDOM PASSWORD
| IDENTIFIED WITH *auth_plugin*
| IDENTIFIED WITH *auth_plugin* BY '*auth_string*'
| IDENTIFIED WITH *auth_plugin* BY RANDOM PASSWORD
| IDENTIFIED WITH *auth_plugin* AS '*auth_string*'
}
*initial_auth_option*: {
INITIAL AUTHENTICATION IDENTIFIED BY {RANDOM PASSWORD | '*auth_string*'}
| INITIAL AUTHENTICATION IDENTIFIED WITH *auth_plugin* AS '*auth_string*'
}
*tls_option*: {
SSL
| X509
| CIPHER '*cipher*'
| ISSUER '*issuer*'
| SUBJECT '*subject*'
}
*resource_option*: {
MAX_QUERIES_PER_HOUR *count*
| MAX_UPDATES_PER_HOUR *count*
| MAX_CONNECTIONS_PER_HOUR *count*
| MAX_USER_CONNECTIONS *count*
}
*password_option*: {
PASSWORD EXPIRE [DEFAULT | NEVER | INTERVAL *N* DAY]
| PASSWORD HISTORY {DEFAULT | *N*}
| PASSWORD REUSE INTERVAL {DEFAULT | *N* DAY}
| PASSWORD REQUIRE CURRENT [DEFAULT | OPTIONAL]
| FAILED_LOGIN_ATTEMPTS *N*
| PASSWORD_LOCK_TIME {*N* | UNBOUNDED}
}
*lock_option*: {
ACCOUNT LOCK
| ACCOUNT UNLOCK
}
CREATE USER语句创建新的 MySQL 账户。它使得可以为新账户建立认证、角色、SSL/TLS、资源限制、密码管理、注释和属性属性。它还控制了账户最初是锁定还是解锁的状态。
要使用CREATE USER,您必须具有全局CREATE USER权限,或者对mysql系统模式具有INSERT权限。当启用read_only系统变量时,CREATE USER还需要CONNECTION_ADMIN权限(或已弃用的SUPER权限)。
截至 MySQL 8.0.27,以下附加特权考虑因素适用:
-
authentication_policy系统变量对CREATE USER语句中与认证相关的子句的使用施加了一定的约束;详情请参阅该变量的描述。如果具有AUTHENTICATION_POLICY_ADMIN权限,则这些约束不适用。 -
要创建一个使用无密码认证的账户,您必须具有
PASSWORDLESS_USER_ADMIN权限。
截至 MySQL 8.0.22,如果要创建的任何账户被命名为任何存储对象的DEFINER属性,则CREATE USER将失败并显示错误。(也就是说,如果创建账户会导致该账户接管当前孤立的存储对象,则该语句将失败。)要执行该操作,您必须具有SET_USER_ID权限;在这种情况下,该语句将以警告成功而不是错误失败。如果没有SET_USER_ID,要执行用户创建操作,请删除孤立对象,创建账户并授予其权限,然后重新创建已删除的对象。有关更多信息,包括如何识别哪些对象将给定账户命名为DEFINER属性,请参阅孤立存储对象。
CREATE USER 对所有命名用户都成功,或者如果发生任何错误则回滚并不起作用。默认情况下,如果尝试创建已存在的用户,则会发生错误。如果给出了 IF NOT EXISTS 子句,则该语句会对每个已存在的命名用户产生警告,而不是错误。
重要提示
在某些情况下,CREATE USER 可能会记录在服务器日志中或客户端的历史文件中,例如 ~/.mysql_history,这意味着明文密码可能被任何具有读取权限的人读取。有关在服务器日志中发生这种情况的条件以及如何控制它的信息,请参见 第 8.1.2.3 节,“密码和日志记录”。有关客户端日志记录的类似信息,请参见 第 6.5.1.3 节,“mysql 客户端日志记录”。
CREATE USER 语句有几个方面,描述如下主题:
-
创建用户概述
-
创建用户认证选项
-
创建用户多因素认证选项
-
创建用户角色选项
-
创建用户 SSL/TLS 选项
-
创建用户资源限制选项
-
创建用户密码管理选项
-
创建用户注释和属性选项
-
创建用户账户锁定选项
-
创建用户二进制日志记录
创建用户概述
对于每个账户,CREATE USER 在 mysql.user 系统表中创建一行新记录。账户行反映了语句中指定的属性。未指定的属性将设置为它们的默认值:
-
认证:默认认证插件(如 默认认证插件 中所述确定的),以及空凭据
-
默认角色:
NONE -
SSL/TLS:
NONE -
资源限制:无限制
-
密码管理:
PASSWORD EXPIRE DEFAULT PASSWORD HISTORY DEFAULT PASSWORD REUSE INTERVAL DEFAULT PASSWORD REQUIRE CURRENT DEFAULT;禁用了失败登录跟踪和临时帐户锁定 -
帐户锁定:
ACCOUNT UNLOCK
创建时,帐户没有任何权限和默认角色NONE。要为此帐户分配权限或角色,请使用一个或多个GRANT语句。
每个帐户名称都采用第 8.2.4 节,“指定帐户名称”中描述的格式。例如:
CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY '*password*';
如果帐户名称的主机名部分被省略,则默认为'%'。您应该知道,虽然 MySQL 8.0 将授予此类用户的授权视为已授予'*user*'@'localhost',但此行为已在 MySQL 8.0.35 中被弃用,并因此可能在将来的 MySQL 版本中被移除。
每个命名帐户的*user值后面可以跟一个可选的auth_option值,表示帐户的认证方式。这些值可以指定帐户认证插件和凭据(例如密码)。每个auth_option*值仅适用于紧随其后的帐户。
根据*user规范,语句可以包括 SSL/TLS、资源限制、密码管理和锁定属性的选项。所有这些选项都是语句的全局属性,并适用于语句中命名的所有*帐户。
示例:创建一个使用默认认证插件和给定密码的帐户。标记密码已过期,以便用户必须在首次连接到服务器时选择新密码:
CREATE USER 'jeffrey'@'localhost'
IDENTIFIED BY '*new_password*' PASSWORD EXPIRE;
示例:创建一个使用caching_sha2_password认证插件和给定密码的帐户。要求每 180 天选择一个新密码,并启用失败登录跟踪,以便三次连续输入错误密码导致帐户被临时锁定两天:
CREATE USER 'jeffrey'@'localhost'
IDENTIFIED WITH caching_sha2_password BY '*new_password*'
PASSWORD EXPIRE INTERVAL 180 DAY
FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 2;
示例:创建多个帐户,指定一些每个帐户的属性和一些全局属性:
CREATE USER
'jeffrey'@'localhost' IDENTIFIED WITH mysql_native_password
BY '*new_password1*',
'jeanne'@'localhost' IDENTIFIED WITH caching_sha2_password
BY '*new_password2*'
REQUIRE X509 WITH MAX_QUERIES_PER_HOUR 60
PASSWORD HISTORY 5
ACCOUNT LOCK;
每个*auth_option*值(在本例中为IDENTIFIED WITH ... BY)仅适用于紧随其后的帐户,因此每个帐户使用紧随其后的认证插件和密码。
剩余的属性全局适用于语句中命名的所有帐户,因此对于两个帐户:
-
必须使用有效的 X.509 证书进行连接。
-
每小时最多允许 60 个查询。
-
密码更改不能重复使用最近的五个密码。
-
帐户最初被锁定,因此实际上它是一个占位符,直到管理员解锁它才能使用。
创建用户认证选项
帐户名称后面可以跟一个*auth_option*认证选项,指定帐户认证插件、凭据或两者。
注意
在 MySQL 8.0.27 之前,auth_option 定义了账户进行身份验证的唯一方法。也就是说,所有账户都使用单因素/单因素身份验证(1FA/SFA)。MySQL 8.0.27 及更高版本支持多因素身份验证(MFA),因此账户可以使用最多三种身份验证方法。也就是说,账户可以使用双因素身份验证(2FA)或三因素身份验证(3FA)。auth_option 的语法和语义保持不变,但*auth_option* 可以后跟额外身份验证方法的规范。本节描述了*auth_option*。有关可选 MFA 相关后续子句的详细信息,请参阅 CREATE USER 多因素身份验证选项。
注意
仅适用于使用将凭据存储在 MySQL 内部的身份验证插件的账户的随机密码生成子句。对于使用针对 MySQL 外部凭据系统执行身份验证的插件的账户,密码管理也必须在该系统外部处理。有关内部凭据存储的更多信息,请参阅 第 8.2.15 节,“密码管理”。
-
auth_plugin指定了一个身份验证插件。插件名称可以是带引号的字符串文字或未带引号的名称。插件名称存储在mysql.user系统表的plugin列中。对于未指定身份验证插件的*
auth_option* 语法,服务器会分配默认插件,具体确定方法请参见 默认身份验证插件。有关每个插件的描述,请参见 第 8.4.1 节,“身份验证插件”。 -
存储在内部的凭据存储在
mysql.user系统表中。'*auth_string*'值或RANDOM PASSWORD指定账户凭据,可以是明文(未加密)字符串或以与账户关联的身份验证插件期望的格式进行哈希处理:-
对于使用
BY '*auth_string*'语法的情况,字符串是明文的,并传递给身份验证插件进行可能的哈希处理。插件返回的结果存储在mysql.user表中。插件可以按照指定的值使用该值,这种情况下不会发生哈希处理。 -
对于使用
BY RANDOM PASSWORD语法的情况,MySQL 生成一个随机密码并以明文形式传递给身份验证插件进行可能的哈希处理。插件返回的结果存储在mysql.user表中。插件可以按照指定的值使用该值,这种情况下不会发生哈希处理。随机生成的密码可在 MySQL 8.0.18 中使用,并具有随机密码生成中描述的特性。
-
对于使用
AS '*auth_string*'语法的语法,假定字符串已经是认证插件所需的格式,并按原样存储在mysql.user表中。如果插件需要哈希值,则该值必须已经以适合插件的格式进行哈希处理;否则,插件无法使用该值,客户端连接的正确认证也不会发生。截至 MySQL 8.0.17,哈希字符串可以是字符串文字或十六进制值。当启用
print_identified_with_as_hex系统变量时,后者对应于包含不可打印字符的密码哈希的值类型,该变量由SHOW CREATE USER显示。 -
如果认证插件不对认证字符串进行哈希处理,则
BY '*auth_string*'和AS '*auth_string*'子句具有相同的效果:认证字符串按原样存储在mysql.user系统表中。
-
CREATE USER允许这些*auth_option*语法:
-
IDENTIFIED BY '*auth_string*'将帐户认证插件设置为默认插件,将明文
'*auth_string*'值传递给插件进行可能的哈希处理,并将结果存储在mysql.user系统表中的帐户行中。 -
IDENTIFIED BY RANDOM PASSWORD将帐户认证插件设置为默认插件,生成随机密码,将明文密码值传递给插件进行可能的哈希处理,并将结果存储在
mysql.user系统表中的帐户行中。该语句还将明文密码作为结果集返回,以便用户或执行该语句的应用程序可以使用。有关结果集和随机生成密码的特性的详细信息,请参见随机密码生成。 -
IDENTIFIED WITH *auth_plugin*将帐户认证插件设置为*
auth_plugin*,将凭据清除为空字符串,并将结果存储在mysql.user系统表中的帐户行中。 -
IDENTIFIED WITH *auth_plugin* BY '*auth_string*'将帐户认证插件设置为*
auth_plugin*,将明文'*auth_string*'值传递给插件进行可能的哈希处理,并将结果存储在mysql.user系统表中的帐户行中。 -
IDENTIFIED WITH *auth_plugin* BY RANDOM PASSWORD将账户认证插件设置为
auth_plugin,生成一个随机密码,将明文密码值传递给插件进行可能的哈希处理,并将结果存储在mysql.user系统表中的账户行中。该语句还将明文密码作为结果集返回,以便用户或执行该语句的应用程序可以访问。有关结果集和随机生成密码的特性的详细信息,请参阅 随机密码生成。 -
IDENTIFIED WITH *auth_plugin* AS '*auth_string*'将账户认证插件设置为
auth_plugin,并将'*auth_string*'值原样存储在mysql.user账户行中。如果插件需要哈希字符串,则假定字符串已经以插件所需的格式进行了哈希处理。
示例:将密码指定为明文;使用默认插件:
CREATE USER 'jeffrey'@'localhost'
IDENTIFIED BY '*password*';
示例:指定认证插件,以及明文密码值:
CREATE USER 'jeffrey'@'localhost'
IDENTIFIED WITH mysql_native_password BY '*password*';
在每种情况下,存储在账户行中的密码值是与账户关联的认证插件对其进行哈希后的明文值 '*password*'。
有关设置密码和认证插件的其他信息,请参阅 第 8.2.14 节,“分配账户密码” 和 第 8.2.17 节,“可插拔认证”。
创建用户多因素认证选项
CREATE USER 中的 auth_option 部分定义了一种用于单因素认证(1FA/SFA)的认证方法。从 MySQL 8.0.27 开始,CREATE USER 具有支持多因素认证(MFA)的子句,因此账户可以拥有最多三种认证方法。也就是说,账户可以使用双因素认证(2FA)或三因素认证(3FA)。
authentication_policy 系统变量定义了带有多因素认证(MFA)子句的 CREATE USER 语句的约束条件。例如,authentication_policy 设置控制了账户可以拥有的认证因素数量,以及对于每个因素,允许使用的认证方法。请参阅 配置多因素认证策略。
关于确定未指定插件名称的认证子句的默认认证插件的特定规则的信息,请参见默认认证插件。
在*auth_option*之后,可能会出现不同的可选 MFA 子句:
-
2fa_auth_option:指定二要素认证方法。以下示例将caching_sha2_password定义为第一要素认证方法,将authentication_ldap_sasl定义为第二要素认证方法。CREATE USER 'u1'@'localhost' IDENTIFIED WITH caching_sha2_password BY '*sha2_password*' AND IDENTIFIED WITH authentication_ldap_sasl AS 'uid=u1_ldap,ou=People,dc=example,dc=com'; -
3fa_auth_option:在*2fa_auth_option之后,可能会出现一个3fa_auth_option*子句,用于指定第三要素认证方法。以下示例将caching_sha2_password定义为第一要素认证方法,将authentication_ldap_sasl定义为第二要素认证方法,将authentication_fido定义为第三要素认证方法。CREATE USER 'u1'@'localhost' IDENTIFIED WITH caching_sha2_password BY '*sha2_password*' AND IDENTIFIED WITH authentication_ldap_sasl AS 'uid=u1_ldap,ou=People,dc=example,dc=com' AND IDENTIFIED WITH authentication_fido; -
initial_auth_option:指定用于配置 FIDO 无密码认证的初始认证方法。如下所示,需要使用生成的随机密码或用户指定的*auth-string*进行临时认证,以启用 FIDO 无密码认证。CREATE USER *user* IDENTIFIED WITH authentication_fido INITIAL AUTHENTICATION IDENTIFIED BY {RANDOM PASSWORD | '*auth_string*'};有关使用 FIDO 可插拔认证配置无密码认证的信息,请参见 FIDO 无密码认证。
创建用户角色选项
DEFAULT ROLE子句定义了用户连接到服务器并进行身份验证时或用户在会话期间执行SET ROLE DEFAULT语句时激活的角色。
每个角色名称使用第 8.2.5 节,“指定角色名称”中描述的格式。例如:
CREATE USER 'joe'@'10.0.0.1' DEFAULT ROLE administrator, developer;
如果省略角色名称的主机名部分,默认为'%'。
DEFAULT ROLE子句允许一个或多个逗号分隔的角色名称列表。这些角色必须在执行CREATE USER时存在;否则语句会引发错误(ER_USER_DOES_NOT_EXIST),并且用户不会被创建。
创建用户 SSL/TLS 选项
MySQL 可以检查 X.509 证书属性,除了基于用户名和凭据的通常认证外。有关在 MySQL 中使用 SSL/TLS 的背景信息,请参见第 8.3 节,“使用加密连接”。
要为 MySQL 账户指定与 SSL/TLS 相关的选项,请使用指定一个或多个*tls_option*值的REQUIRE子句。
REQUIRE选项的顺序不重要,但不能指定两次选项。REQUIRE选项之间的AND关键字是可选的。
CREATE USER 允许这些 tls_option 值:
-
NONE表示语句指定的所有帐户没有 SSL 或 X.509 要求。如果用户名和密码有效,则允许未加密连接。如果客户端具有正确的证书和密钥文件,则客户端可以选择使用加密连接。
CREATE USER 'jeffrey'@'localhost' REQUIRE NONE;客户端默认尝试建立安全连接。对于具有
REQUIRE NONE的客户端,如果无法建立安全连接,则连接尝试回退到未加密连接。要求加密连接,客户端只需指定--ssl-mode=REQUIRED选项;如果无法建立安全连接,则连接尝试失败。如果未指定任何与 SSL 相关的
REQUIRE选项,则NONE是默认值。 -
SSL通知服务器只允许通过语句指定的所有帐户进行加密连接。
CREATE USER 'jeffrey'@'localhost' REQUIRE SSL;客户端默认尝试建立安全连接。对于具有
REQUIRE SSL的帐户,如果无法建立安全连接,则连接尝试失败。 -
X509对于语句指定的所有帐户,要求客户端提供有效证书,但确切的证书、颁发者和主题并不重要。唯一的要求是应该能够使用其中一个 CA 证书验证其签名。使用 X.509 证书始终意味着加密,因此在这种情况下
SSL选项是不必要的。CREATE USER 'jeffrey'@'localhost' REQUIRE X509;对于具有
REQUIRE X509的帐户,客户端必须指定--ssl-key和--ssl-cert选项进行连接。(建议但不是必须还指定--ssl-ca,以便验证服务器提供的公共证书。)对于ISSUER和SUBJECT也是如此,因为这些REQUIRE选项暗示了X509的要求。 -
ISSUER '*issuer*'对于语句指定的所有帐户,要求客户端提供由 CA
'*issuer*'颁发的有效 X.509 证书。如果客户端提供的证书有效但颁发者不同,则服务器拒绝连接。使用 X.509 证书始终意味着加密,因此在这种情况下SSL选项是不必要的。CREATE USER 'jeffrey'@'localhost' REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/ O=MySQL/CN=CA/emailAddress=ca@example.com';因为
ISSUER暗示了X509的要求,客户端必须指定--ssl-key和--ssl-cert选项进行连接。(建议但不是必须还指定--ssl-ca,以便验证服务器提供的公共证书。) -
SUBJECT '*subject*'对于陈述中命名的所有帐户,要求客户端提供包含主题*
subject*的有效 X.509 证书。如果客户端提供了一个有效但主题不同的证书,服务器将拒绝连接。使用 X.509 证书总是意味着加密,因此在这种情况下SSL选项是不必要的。CREATE USER 'jeffrey'@'localhost' REQUIRE SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/ O=MySQL demo client certificate/ CN=client/emailAddress=client@example.com';MySQL 对
'*subject*'值与证书中的值进行简单的字符串比较,因此字母大小写和组件顺序必须与证书中的完全一致。因为
SUBJECT暗示了X509的要求,客户端必须指定--ssl-key和--ssl-cert选项进行连接。(建议但不是必须还指定--ssl-ca,以便验证服务器提供的公共证书。) -
CIPHER '*cipher*'对于陈述中命名的所有帐户,需要为加密连接指定特定的密码方法。这个选项是必需的,以确保使用足够强度的密码和密钥长度。如果使用旧算法和短加密密钥,加密可能会很弱。
CREATE USER 'jeffrey'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA';
SUBJECT、ISSUER和CIPHER选项可以在REQUIRE子句中组合使用:
CREATE USER 'jeffrey'@'localhost'
REQUIRE SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/
O=MySQL demo client certificate/
CN=client/emailAddress=client@example.com'
AND ISSUER '/C=SE/ST=Stockholm/L=Stockholm/
O=MySQL/CN=CA/emailAddress=ca@example.com'
AND CIPHER 'EDH-RSA-DES-CBC3-SHA';
创建用户资源限制选项
可以通过讨论中提到的第 8.2.21 节,“设置帐户资源限制”来限制帐户对服务器资源的使用。为此,请使用指定一个或多个*resource_option*值的WITH子句。
WITH选项的顺序无关紧要,除非给定资源限制被多次指定,最后一次实例优先。
CREATE USER允许这些*resource_option*值:
-
MAX_QUERIES_PER_HOUR *count*,MAX_UPDATES_PER_HOUR *count*,MAX_CONNECTIONS_PER_HOUR *count*对于陈述中命名的所有帐户,这些选项限制了每个帐户在任何给定的一个小时内对服务器的查询、更新和连接的次数。如果*
count*是0(默认值),这意味着该帐户没有限制。 -
MAX_USER_CONNECTIONS *count*对于陈述中命名的所有帐户,限制了每个帐户对服务器的最大同时连接数。非零的*
count明确指定了该帐户的限制。如果count*是0(默认值),服务器从max_user_connections系统变量的全局值确定该帐户的同时连接数。如果max_user_connections也是零,则该帐户没有限制。
示例:
CREATE USER 'jeffrey'@'localhost'
WITH MAX_QUERIES_PER_HOUR 500 MAX_UPDATES_PER_HOUR 100;
创建用户密码管理选项
创建用户 支持几个*password_option*值用于密码管理:
-
密码过期选项:您可以手动使账户密码过期并建立其密码过期策略。策略选项不会使密码过期。相反,它们确定服务器如何根据密码年龄自动使账户过期,密码年龄是从最近一次账户密码更改的日期和时间开始评估的。
-
密码重用选项:您可以基于密码更改次数、经过的时间或两者限制密码重用。
-
需要密码验证的选项:您可以指示尝试更改账户密码是否必须指定当前密码,以验证试图进行更改的用户实际上知道当前密码。
-
不正确密码失败登录跟踪选项:您可以导致服务器跟踪失败的登录尝试,并临时锁定给出太多连续不正确密码的账户。失败次数和锁定时间可配置。
本节描述了密码管理选项的语法。有关建立密码管理策略的信息,请参阅第 8.2.15 节,“密码管理”。
如果指定了给定类型的多个密码管理选项,则最后一个优先。例如,密码过期默认 密码过期从不等同于密码过期从不。
注意
除了与失败登录跟踪相关的选项外,密码管理选项仅适用于使用将凭据存储在 MySQL 内部的身份验证插件的账户。对于使用针对 MySQL 外部凭据系统执行身份验证的插件的账户,密码管理也必须在该系统外部处理。有关内部凭据存储的更多信息,请参阅第 8.2.15 节,“密码管理”。
如果账户密码已被手动过期或密码年龄被认为大于其允许的生命周期根据自动过期策略。在这种情况下,服务器要么断开客户端连接,要么限制其允许的操作(请参阅第 8.2.16 节,“过期密码的服务器处理”)。受限客户端执行的操作会导致错误,直到用户建立新的账户密码。
创建用户 允许这些*password_option*值来控制密码过期:
-
密码过期立即标记语句命名的所有账户的密码过期。
CREATE USER 'jeffrey'@'localhost' PASSWORD EXPIRE; -
密码过期默认设置所有语句中命名的帐户,使全局过期策略适用,如
default_password_lifetime系统变量指定的那样。CREATE USER 'jeffrey'@'localhost' PASSWORD EXPIRE DEFAULT; -
PASSWORD EXPIRE NEVER此过期选项覆盖了语句中命名的所有帐户的全局策略。对于每个帐户,它禁用密码过期,使密码永不过期。
CREATE USER 'jeffrey'@'localhost' PASSWORD EXPIRE NEVER; -
PASSWORD EXPIRE INTERVAL *N* DAY此过期选项覆盖了语句中命名的所有帐户的全局策略。对于每个帐户,它将密码寿命设置为*
N*天。以下语句要求每 180 天更改一次密码:CREATE USER 'jeffrey'@'localhost' PASSWORD EXPIRE INTERVAL 180 DAY;
CREATE USER允许这些*password_option*值来控制基于所需最小密码更改次数的先前密码重用:
-
PASSWORD HISTORY DEFAULT设置所有语句中命名的帐户,使全局关于密码历史长度的策略适用,以禁止在
password_history系统变量指定的更改次数之前重用密码。CREATE USER 'jeffrey'@'localhost' PASSWORD HISTORY DEFAULT; -
PASSWORD HISTORY *N*此历史长度选项覆盖了语句中命名的所有帐户的全局策略。对于每个帐户,它将密码历史长度设置为*
N个密码,以禁止重用最近选择的N*个密码中的任何一个。以下语句禁止重用之前的 6 个密码中的任何一个:CREATE USER 'jeffrey'@'localhost' PASSWORD HISTORY 6;
CREATE USER允许这些*password_option*值来控制基于经过时间的先前密码重用:
-
PASSWORD REUSE INTERVAL DEFAULT设置所有帐户中命名的语句,使全局关于经过时间的策略适用,以禁止重用新于
password_reuse_interval系统变量指定的天数的密码。CREATE USER 'jeffrey'@'localhost' PASSWORD REUSE INTERVAL DEFAULT; -
PASSWORD REUSE INTERVAL *N* DAY此经过时间选项覆盖了语句中命名的所有帐户的全局策略。对于每个帐户,它将密码重用间隔设置为*
N*天,以禁止重用新于该天数的密码。以下语句禁止密码在 360 天内重用:CREATE USER 'jeffrey'@'localhost' PASSWORD REUSE INTERVAL 360 DAY;
CREATE USER允许这些*password_option*值来控制是否尝试更改帐户密码必须指定当前密码,以验证尝试进行更改的用户实际上知道当前密码:
-
PASSWORD REQUIRE CURRENT此验证选项覆盖了语句中命名的所有帐户的全局策略。对于每个帐户,它要求密码更改时指定当前密码。
CREATE USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT; -
PASSWORD REQUIRE CURRENT OPTIONAL此验证选项会覆盖语句指定的所有帐户的全局策略。对于每个帐户,不需要密码更改指定当前密码。(当前密码可以给出,但不是必需的。)
CREATE USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT OPTIONAL; -
PASSWORD REQUIRE CURRENT DEFAULT设置所有由帐户命名的语句,以便全局关于密码验证的策略适用,如
password_require_current系统变量所指定的那样。CREATE USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT DEFAULT;
从 MySQL 8.0.19 开始,CREATE USER 允许这些 password_option 值来控制登录失败跟踪:
-
FAILED_LOGIN_ATTEMPTS *N*是否跟踪指定错误密码的帐户登录尝试。
N必须是从 0 到 32767 的数字。值为 0 会禁用登录失败跟踪。大于 0 的值表示多少连续密码失败会导致临时帐户锁定(如果PASSWORD_LOCK_TIME也是非零)。 -
PASSWORD_LOCK_TIME {*N* | UNBOUNDED}连续登录尝试提供错误密码后锁定帐户的时间。
N必须是从 0 到 32767 的数字,或者UNBOUNDED。值为 0 会禁用临时帐户锁定。大于 0 的值表示锁定帐户的天数。值为UNBOUNDED会导致帐户锁定持续时间无限制;一旦锁定,帐户将保持锁定状态直到解锁。有关解锁发生的条件的信息,请参阅登录失败跟踪和临时帐户锁定。
要进行登录失败跟踪和临时锁定,帐户的 FAILED_LOGIN_ATTEMPTS 和 PASSWORD_LOCK_TIME 选项都必须非零。以下语句创建一个帐户,在连续四次密码失败后保持锁定两天:
CREATE USER 'jeffrey'@'localhost'
FAILED_LOGIN_ATTEMPTS 4 PASSWORD_LOCK_TIME 2;
创建用户注释和属性选项
从 MySQL 8.0.21 开始,您可以创建一个带有可选注释或属性的帐户,如下所述:
-
用户注释
要设置用户注释,请在
CREATE USER语句中添加COMMENT '*user_comment*',其中user_comment是用户注释的文本。示例(省略其他选项):
CREATE USER 'jon'@'localhost' COMMENT 'Some information about Jon'; -
用户属性
用户属性是由一个或多个键值对组成的 JSON 对象,并通过在
CREATE USER中包含ATTRIBUTE '*json_object*'来设置。json_object必须是一个有效的 JSON 对象。示例(省略其他选项):
CREATE USER 'jim'@'localhost' ATTRIBUTE '{"fname": "James", "lname": "Scott", "phone": "123-456-7890"}';
用户注释和用户属性一起存储在信息模式 USER_ATTRIBUTES 表的 ATTRIBUTE 列中。此查询显示了刚刚用于创建用户 jim@localhost 的语句插入的此表中的行:
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER = 'jim' AND HOST = 'localhost'\G
*************************** 1\. row ***************************
USER: jim
HOST: localhost
ATTRIBUTE: {"fname": "James", "lname": "Scott", "phone": "123-456-7890"} 1 row in set (0.00 sec)
实际上,COMMENT选项提供了一个快捷方式,用于设置一个只有comment作为其键且其值为选项提供的参数的用户属性。通过执行语句CREATE USER 'jon'@'localhost' COMMENT 'Some information about Jon',并观察它插入到USER_ATTRIBUTES表中的行,您可以看到这一点:
mysql> CREATE USER 'jon'@'localhost' COMMENT 'Some information about Jon';
Query OK, 0 rows affected (0.06 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER = 'jon' AND HOST = 'localhost';
+------+-----------+-------------------------------------------+
| USER | HOST | ATTRIBUTE |
+------+-----------+-------------------------------------------+
| jon | localhost | {"comment": "Some information about Jon"} |
+------+-----------+-------------------------------------------+
1 row in set (0.00 sec)
不能在同一CREATE USER语句中同时使用COMMENT和ATTRIBUTE;尝试这样做会导致语法错误。要同时设置用户评论和用户属性,使用ATTRIBUTE并在其参数中包含具有comment键的值,如下所示:
mysql> CREATE USER 'bill'@'localhost'
-> ATTRIBUTE '{"fname":"William", "lname":"Schmidt",
-> "comment":"Website developer"}';
Query OK, 0 rows affected (0.16 sec)
由于ATTRIBUTE行的内容是一个 JSON 对象,您可以使用任何适当的 MySQL JSON 函数或运算符来操作它,如下所示:
mysql> SELECT
-> USER AS User,
-> HOST AS Host,
-> CONCAT(ATTRIBUTE->>"$.fname"," ",ATTRIBUTE->>"$.lname") AS 'Full Name',
-> ATTRIBUTE->>"$.comment" AS Comment
-> FROM INFORMATION_SCHEMA.USER_ATTRIBUTES
-> WHERE USER='bill' AND HOST='localhost';
+------+-----------+-----------------+-------------------+
| User | Host | Full Name | Comment |
+------+-----------+-----------------+-------------------+
| bill | localhost | William Schmidt | Website developer |
+------+-----------+-----------------+-------------------+
1 row in set (0.00 sec)
要为现有用户设置或更改用户评论或用户属性,可以使用带有ALTER USER语句的COMMENT或ATTRIBUTE选项。
因为用户评论和用户属性在单个JSON列中内部存储在一起,这为它们的最大组合大小设置了一个上限;有关更多信息,请参阅 JSON 存储要求。
有关更多信息和示例,请参阅信息模式USER_ATTRIBUTES表的描述。
创建用户帐户锁定选项
MySQL 支持使用ACCOUNT LOCK和ACCOUNT UNLOCK选项对帐户进行锁定和解锁,这些选项指定帐户的锁定状态。有关更多讨论,请参阅 Section 8.2.20,“帐户锁定”。
如果指定了多个帐户锁定选项,则最后一个优先。
创建用户二进制日志
如果CREATE USER成功,则写入二进制日志,但如果失败则不写入;在这种情况下,将发生回滚并且不会进行任何更改。写入二进制日志的语句包括所有命名用户。如果给出了IF NOT EXISTS子句,这甚至包括已经存在且未创建的用户。
写入二进制日志的语句为每个用户指定一个身份验证插件,确定如下:
-
原始语句中指定的插件。
-
否则,默认的身份验证插件。特别是,如果用户
u1已经存在并使用非默认身份验证插件,则为CREATE USER IF NOT EXISTS u1写入二进制日志的语句将列出默认身份验证插件。(如果必须为用户指定非默认身份验证插件,请在原始语句中包含它。)
如果服务器为二进制日志中写入的任何不存在的用户添加默认身份验证插件,则会在错误日志中写入警告,列出这些用户的名称。
如果原始语句指定了FAILED_LOGIN_ATTEMPTS或PASSWORD_LOCK_TIME选项,则写入二进制日志的语句将包括该选项。
支持多因素认证(MFA)的子句的CREATE USER语句将写入二进制日志。
CREATE USER ... IDENTIFIED WITH .. INITIAL AUTHENTICATION IDENTIFIED WITH ...语句将作为CREATE USER .. IDENTIFIED WITH .. INITIAL AUTHENTICATION IDENTIFIED WITH .. AS '*password-hash*'写入二进制日志,其中*password-hash是用户指定的auth-string*或服务器在指定RANDOM PASSWORD子句时生成的随机密码。
15.7.1.4 DROP ROLE Statement
DROP ROLE [IF EXISTS] *role* [, *role* ] ...
DROP ROLE 移除一个或多个角色(具有特权的命名集合)。要使用此语句,您必须具有全局DROP ROLE或CREATE USER特权。当启用read_only系统变量时,DROP ROLE 还需要CONNECTION_ADMIN特权(或已弃用的SUPER特权)。
从 MySQL 8.0.16 开始,具有CREATE USER特权的用户可以使用此语句删除已锁定或未锁定的账户。具有DROP ROLE特权的用户只能使用此语句删除已锁定的账户(未锁定的账户可能是用于登录到服务器的用户账户,而不仅仅是角色)。
在mandatory_roles系统变量值中命名的角色不能被删除。
DROP ROLE 对所有命名角色要么成功,要么回滚并且如果发生任何错误则不会产生影响。默认情况下,如果尝试删除不存在的角色,则会发生错误。如果给出了IF EXISTS子句,则该语句会对每个不存在的命名角色产生警告,而不是错误。
如果成功,该语句将被写入二进制日志,但如果失败则不会;在这种情况下,将发生回滚并且不会进行任何更改。写入二进制日志的语句包括所有命名角色。如果给出了IF EXISTS子句,则即使是不存在且未被删除的角色也会被包括在内。
每个角色名称使用第 8.2.5 节“指定角色名称”中描述的格式。例如:
DROP ROLE 'admin', 'developer';
DROP ROLE 'webapp'@'localhost';
如果省略角色名称的主机名部分,默认为'%'。
一个被撤销的角色会自动从授予该角色的任何用户账户(或角色)中撤销。在该账户的任何当前会话中,其调整后的特权将从执行下一个语句开始生效。
有关角色使用示例,请参见第 8.2.10 节“使用角色”。
15.7.1.5 DROP USER 语句
DROP USER [IF EXISTS] *user* [, *user*] ...
DROP USER 语句会移除一个或多个 MySQL 账户及其权限。它会从所有授权表中移除该账户的权限行。
在 mandatory_roles 系统变量值中命名的角色不能被删除。
要使用 DROP USER,你必须拥有全局的 CREATE USER 权限,或者对 mysql 系统模式拥有 DELETE 权限。当启用 read_only 系统变量时,DROP USER 还需要 CONNECTION_ADMIN 权限(或者已弃用的 SUPER 权限)。
截至 MySQL 8.0.22 版本,如果要删除的任何账户被命名为任何存储对象的 DEFINER 属性,则 DROP USER 会因错误而失败。(也就是说,如果删除一个账户会导致存储对象变成孤立状态,则该语句会失败。)要执行该操作,你必须拥有 SET_USER_ID 权限;在这种情况下,该语句会成功并产生警告,而不是失败并产生错误。有关更多信息,包括如何识别哪些对象将给定账户命名为 DEFINER 属性,请参阅 Orphan Stored Objects。
DROP USER 对所有命名用户要么全部成功,要么回滚并且在发生任何错误时不会产生影响。默认情况下,如果尝试删除不存在的用户,则会发生错误。如果给出了 IF EXISTS 子句,则该语句会对每个不存在的命名用户产生警告,而不是错误。
如果成功,该语句会被写入二进制日志,但如果失败则不会;在这种情况下,会发生回滚并且不会有任何更改。写入二进制日志的语句包括所有命名用户。如果给出了 IF EXISTS 子句,则即使用户不存在且未被删除,也会包括这些用户。
每个账户名使用 Section 8.2.4, “Specifying Account Names” 中描述的格式。例如:
DROP USER 'jeffrey'@'localhost';
如果省略账户名的主机名部分,则默认为 '%'。
重要提示
DROP USER 不会自动关闭任何打开的用户会话。相反,如果删除具有打开会话的用户,则该语句直到该用户的会话关闭后才生效。一旦会话关闭,用户被删除,该用户的下一次登录尝试将失败。这是设计上的。
DROP USER 不会自动删除或使旧用户创建的数据库或其中的对象失效。这包括DEFINER属性指定已删除用户的存储过程或视图。如果在定义者安全上下文中执行这些对象,可能会产生错误。(有关安全上下文的信息,请参见第 27.6 节,“存储对象访问控制”。)
15.7.1.6 GRANT 语句
GRANT
*priv_type* [(*column_list*)]
[, *priv_type* [(*column_list*)]] ...
ON [*object_type*] *priv_level*
TO *user_or_role* [, *user_or_role*] ...
[WITH GRANT OPTION]
[AS *user*
[WITH ROLE
DEFAULT
| NONE
| ALL
| ALL EXCEPT *role* [, *role* ] ...
| *role* [, *role* ] ...
]
]
}
GRANT PROXY ON *user_or_role*
TO *user_or_role* [, *user_or_role*] ...
[WITH GRANT OPTION]
GRANT *role* [, *role*] ...
TO *user_or_role* [, *user_or_role*] ...
[WITH ADMIN OPTION]
*object_type*: {
TABLE
| FUNCTION
| PROCEDURE
}
*priv_level*: {
*
| *.*
| *db_name*.*
| *db_name.tbl_name*
| *tbl_name*
| *db_name*.*routine_name*
}
*user_or_role*: {
*user* (see Section 8.2.4, “Specifying Account Names”)
| *role* (see Section 8.2.5, “Specifying Role Names”)
}
GRANT 语句将特权和角色分配给 MySQL 用户账户和角色。GRANT 语句有几个方面,描述如下主题:
-
GRANT 概述
-
对象引用指南
-
账户名称
-
MySQL 支持的特权
-
全局特权
-
数据库特权
-
表特权
-
列特权
-
存储过程特权
-
代理用户特权
-
授予角色
-
AS子句和特权限制 -
其他账户特性
-
MySQL 和标准 SQL 版本的 GRANT
GRANT 概述
GRANT 语句使系统管理员能够授予特权和角色,这些可以授予给用户账户和角色。这些语法限制适用:
-
GRANT不能在同一语句中混合授予特权和角色。给定的GRANT语句必须授予特权或角色之一。 -
ON子句区分语句是授予特权还是角色:-
有了
ON,该语句授予特权。 -
没有
ON,该语句授予角色。 -
允许将特权和角色同时分配给一个账户,但必须使用单独的
GRANT语句,每个语句的语法适用于所要授予的内容。
-
有关角色的更多信息,请参见 第 8.2.10 节,“使用角色”。
要使用GRANT授予特权,您必须具有GRANT OPTION特权,并且必须具有您正在授予的特权。 (或者,如果您对mysql系统模式中的授权表具有UPDATE特权,则可以授予任何账户任何特权。)当启用read_only系统变量时,GRANT还需要CONNECTION_ADMIN特权(或已弃用的SUPER特权)。
GRANT对所有指定的用户和角色都成功时才会成功,如果出现任何错误,则会回滚并且不会产生任何效果。只有当对所有指定的用户和角色都成功时,该语句才会被写入二进制日志。
REVOKE语句与GRANT相关,允许管理员撤销账户特权。参见 Section 15.7.1.8, “REVOKE Statement”。
每个账户名称使用 Section 8.2.4, “Specifying Account Names”中描述的格式。每个角色名称使用 Section 8.2.5, “Specifying Role Names”中描述的格式。例如:
GRANT ALL ON db1.* TO 'jeffrey'@'localhost';
GRANT 'role1', 'role2' TO 'user1'@'localhost', 'user2'@'localhost';
GRANT SELECT ON world.* TO 'role3';
如果省略账户或角色名称的主机名部分,则默认为'%'。
通常,数据库管理员首先使用CREATE USER创建一个账户并定义其非特权特征,如密码、是否使用安全连接以及对服务器资源访问的限制,然后使用GRANT定义其特权。可以使用ALTER USER来更改现有账户的非特权特征。例如:
CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY '*password*';
GRANT ALL ON db1.* TO 'jeffrey'@'localhost';
GRANT SELECT ON db2.invoice TO 'jeffrey'@'localhost';
ALTER USER 'jeffrey'@'localhost' WITH MAX_QUERIES_PER_HOUR 90;
从mysql程序中,当成功执行GRANT时,会显示Query OK, 0 rows affected。要确定操作的结果产生了哪些特权,请使用SHOW GRANTS。参见 Section 15.7.7.21, “SHOW GRANTS Statement”。
重要提示
在某些情况下,GRANT可能会记录在服务器日志中或在客户端的历史文件中,例如~/.mysql_history,这意味着任何具有读取该信息权限的人都可以读取明文密码。有关在服务器日志中发生这种情况的条件以及如何控制它的信息,请参阅第 8.1.2.3 节,“密码和日志记录”。有关客户端日志记录的类似信息,请参阅第 6.5.1.3 节,“mysql 客户端日志记录”。
GRANT支持长达 255 个字符的主机名(在 MySQL 8.0.17 之前为 60 个字符)。用户名最多可达 32 个字符。数据库、表、列和例程名称最多可达 64 个字符。
警告
不要尝试通过修改mysql.user系统表来更改用户名称的允许长度。这样做会导致不可预测的行为,甚至可能使用户无法登录到 MySQL 服务器。除非通过第三章,“升级 MySQL”中描述的过程,否则永远不要以任何方式更改mysql系统模式中表的结构。
对象引用指南
在GRANT语句中,有几个对象需要引用,尽管在许多情况下引用是可选的:账户、角色、数据库、表、列和例程名称。例如,如果账户名中的*user_name或host_name值作为未引用的标识符是合法的,那么你无需对其进行引用。然而,引号是必要的,以指定包含特殊字符(如-)的user_name字符串,或包含特殊字符或通配符字符(例如,'test-user'@'%.com')的host_name*字符串。分别引用用户名和主机名。
要指定引用值:
-
将数据库、表、列和例程名称引用为标识符。
-
将用户名称和主机名引用为标识符或字符串。
-
将密码作为字符串进行引用。
有关字符串引用和标识符引用的指南,请参阅第 11.1.1 节,“字符串文字”和第 11.2 节,“模式对象名称”。
重要
如下几段所述的通配符字符%和_在 MySQL 8.0.35 中已被弃用,因此可能在未来的 MySQL 版本中被移除。
在GRANT语句中指定数据库名称时允许使用_和%通配符(GRANT ... ON *db_name*.*)。这意味着,例如,要在数据库名称中使用_字符,可以在GRANT语句中使用\转义字符指定为\_,以防止用户能够访问与通配符模式匹配的其他数据库(例如,GRANT ... ON foo_bar.* TO ...)。
包含通配符的多个GRANT语句可能对 DML 语句产生意外效果;在解析涉及通配符的授权时,MySQL 只考虑第一个匹配的授权。换句话说,如果一个用户有两个使用通配符匹配同一数据库的数据库级授权,那么将应用首先创建的授权。考虑使用以下语句创建的数据库db和表t:
mysql> CREATE DATABASE db;
Query OK, 1 row affected (0.01 sec)
mysql> CREATE TABLE db.t (c INT);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO db.t VALUES ROW(1);
Query OK, 1 row affected (0.00 sec)
接下来(假设当前账户是 MySQL root账户或具有必要权限的其他账户),我们创建一个用户u,然后发出两个包含通配符的GRANT语句,如下所示:
mysql> CREATE USER u;
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT SELECT ON `d_`.* TO u;
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT INSERT ON `d%`.* TO u;
Query OK, 0 rows affected (0.00 sec)
mysql> EXIT
Bye
如果我们结束会话,然后使用mysql客户端再次登录,这次作为u,我们会发现该账户只有第一个匹配授权提供的权限,而不是第二个:
$> mysql -uu -hlocalhost
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.37-tr Source distribution
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input
statement.
mysql> TABLE db.t;
+------+
| c |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> INSERT INTO db.t VALUES ROW(2);
ERROR 1142 (42000): INSERT command denied to user 'u'@'localhost' for table 't'
在权限分配中,MySQL 在以下情况下将数据库名称中未转义的_和% SQL 通配符字符解释为字面字符:
-
当数据库名称未用于在数据库级别授予权限,而是作为授予权限给其他对象(例如表或例程)的限定符时(例如,
GRANT ... ON *db_name*.*tbl_name*)。 -
启用
partial_revokes会导致 MySQL 将数据库名称中未转义的_和%通配符字符解释为字面字符,就好像它们已经被转义为\_和\%一样。因为这会改变 MySQL 解释权限的方式,建议在可能启用partial_revokes的安装中避免未转义的通配符字符在权限分配中出现。有关更多信息,请参见 Section 8.2.12,“使用部分撤销进行权限限制”。
账户名称
在GRANT语句中的*user值表示适用于该语句的 MySQL 账户。为了允许向来自任意主机的用户授予权限,MySQL 支持以'*user_name*'@'*host_name*'形式指定user*值。
您可以在主机名中指定通配符。例如,'*user_name*'@'%.example.com'适用于example.com域中的*user_name,而'*user_name*'@'198.51.100.%'适用于198.51.100类 C 子网中的user_name*。
简单形式的'*user_name*'是'*user_name*'@'%'的同义词。
注意
MySQL 自动将授予'*username*'@'%'的所有权限也分配给'*username*'@'localhost'帐户。此行为在 MySQL 8.0.35 及更高版本中已弃用,并可能在将来的 MySQL 版本中删除。
MySQL 不支持用户名称中的通配符。要引用匿名用户,请使用带有空用户名称的帐户在GRANT语句中指定:
GRANT ALL ON test.* TO ''@'localhost' ...;
在这种情况下,任何使用正确密码从本地主机连接的用户都被允许访问匿名用户帐户关联的权限。
有关帐户名称中用户名和主机名值的附加信息,请参阅 Section 8.2.4, “Specifying Account Names”。
警告
如果允许本地匿名用户连接到 MySQL 服务器,则还应将所有本地用户的权限授予为'*user_name*'@'localhost'。否则,当命名用户尝试从本地计算机登录到 MySQL 服务器时,将在mysql.user系统表中使用localhost的匿名用户帐户。有关详细信息,请参阅 Section 8.2.6, “Access Control, Stage 1: Connection Verification”。
要确定此问题是否适用于您,请执行以下查询,列出任何匿名用户:
SELECT Host, User FROM mysql.user WHERE User='';
要避免刚才描述的问题,使用以下语句删除本地匿名用户帐户:
DROP USER ''@'localhost';
MySQL 支持的权限
以下表总结了可以为GRANT和REVOKE语句指定的静态和动态*priv_type*权限类型,以及可以授予每个权限的级别。有关每个权限的更多信息,请参阅 Section 8.2.2, “Privileges Provided by MySQL”。有关静态和动态权限之间的区别,请参阅 Static Versus Dynamic Privileges。
Table 15.11 Permissible Static Privileges for GRANT and REVOKE
| 权限 | 意义和可授予级别 |
|---|---|
ALL [PRIVILEGES] | 在指定的访问级别授予所有权限,除了GRANT OPTION和PROXY。 |
ALTER | 启用使用ALTER TABLE。级别:全局,数据库,表。 |
ALTER ROUTINE | 启用存储过程的修改或删除。级别:全局,数据库,存储过程。 |
CREATE | 启用数据库和表的创建。级别:全局,数据库,表。 |
CREATE ROLE | 启用角色的创建。级别:全局。 |
CREATE ROUTINE | 启用存储过程的创建。级别:全局,数据库。 |
CREATE TABLESPACE | 启用创建、修改或删除表空间和日志文件组。级别:全局。 |
CREATE TEMPORARY TABLES | 启用使用CREATE TEMPORARY TABLE。级别:全局,数据库。 |
CREATE USER | 启用使用CREATE USER、DROP USER、RENAME USER和REVOKE ALL PRIVILEGES。级别:全局。 |
CREATE VIEW | 启用视图的创建或修改。级别:全局,数据库,表。 |
DELETE | 启用DELETE的使用。级别:全局,数据库,表。 |
DROP | 启用数据库、表和视图的删除。级别:全局,数据库,表。 |
DROP ROLE | 启用角色的删除。级别:全局。 |
EVENT | 启用事件调度器的事件使用。级别:全局,数据库。 |
EXECUTE | 启用用户执行存储过程。级别:全局,数据库,存储过程。 |
FILE | 启用用户使服务器读取或写入文件。级别:全局。 |
GRANT OPTION | 启用将权限授予或从其他帐户中移除的功能。级别:全局,数据库,表,存储过程,代理。 |
INDEX | 启用索引的创建或删除。级别:全局,数据库,表。 |
INSERT | 启用INSERT的使用。级别:全局,数据库,表,列。 |
LOCK TABLES | 允许在具有SELECT权限的表上使用LOCK TABLES。级别:全局,数据库。 |
PROCESS | 允许用户使用SHOW PROCESSLIST查看所有进程。级别:全局。 |
PROXY | 允许��户代理。级别:从用户到用户。 |
REFERENCES | 允许创建外键。级别:全局,数据库,表,列。 |
RELOAD | 允许使用FLUSH操作。级别:全局。 |
REPLICATION CLIENT | 允许用户查询源或副本服务器的位置。级别:全局。 |
REPLICATION SLAVE | 允许副本从源读取二进制日志事件。级别:全局。 |
SELECT | 允许使用SELECT。级别:全局,数据库,表,列。 |
SHOW DATABASES | 允许使用SHOW DATABASES显示所有数据库。级别:全局。 |
SHOW VIEW | 允许使用SHOW CREATE VIEW。级别:全局,数据库,表。 |
SHUTDOWN | 允许使用mysqladmin shutdown。级别:全局。 |
SUPER | 允许使用其他管理操作,如CHANGE REPLICATION SOURCE TO,CHANGE MASTER TO,KILL,PURGE BINARY LOGS,SET GLOBAL以及mysqladmin debug命令。级别:全局。 |
TRIGGER | 允许触发器操作。级别:全局,数据库,表。 |
UPDATE | 允许使用UPDATE。级别:全局,数据库,表,列。 |
USAGE | “无权限”的同义词 |
| 权限 | 含义和可授权级别 |
表 15.12 GRANT 和 REVOKE 的可允许动态权限
| Privilege | 意义和可授权级别 |
|---|---|
APPLICATION_PASSWORD_ADMIN | 启用双密码管理。级别:全局。 |
AUDIT_ABORT_EXEMPT | 允许通过审计日志过滤器阻止的查询。级别:全局。 |
AUDIT_ADMIN | 启用审计日志配置。级别:全局。 |
AUTHENTICATION_POLICY_ADMIN | 启用认证策略管理。级别:全局。 |
BACKUP_ADMIN | 启用备份管理。级别:全局。 |
BINLOG_ADMIN | 启用二进制日志控制。级别:全局。 |
BINLOG_ENCRYPTION_ADMIN | 启用二进制日志加密的激活和停用。级别:全局。 |
CLONE_ADMIN | 启用克隆管理。级别:全局。 |
CONNECTION_ADMIN | 启用连接限制/限制控制。级别:全局。 |
ENCRYPTION_KEY_ADMIN | 启用InnoDB密钥轮换。级别:全局。 |
FIREWALL_ADMIN | 启用防火墙规则管理,任何用户。级别:全局。 |
FIREWALL_EXEMPT | 免除用户防火墙限制。级别:全局。 |
FIREWALL_USER | 启用防火墙规则管理,自身。级别:全局。 |
FLUSH_OPTIMIZER_COSTS | 启用优化器成本重新加载。级别:全局。 |
FLUSH_STATUS | 启用状态指示器刷新。级别:全局。 |
FLUSH_TABLES | 启用表刷新。级别:全局。 |
FLUSH_USER_RESOURCES | 启用用户资源刷新。级别:全局。 |
GROUP_REPLICATION_ADMIN | 启用组复制控制。级别:全局。 |
INNODB_REDO_LOG_ARCHIVE | 启用重做日志归档管理。级别:全局。 |
INNODB_REDO_LOG_ENABLE | 启用或禁用重做日志记录。级别:全局。 |
NDB_STORED_USER | 启用在 SQL 节点(NDB 集群)之间共享用户或角色。级别:全局。 |
PASSWORDLESS_USER_ADMIN | 启用无密码用户帐户管理。级别:全局。 |
PERSIST_RO_VARIABLES_ADMIN | 启用持久化只读系统变量。级别:全局。 |
REPLICATION_APPLIER | 作为复制通道的PRIVILEGE_CHECKS_USER。级别:全局。 |
REPLICATION_SLAVE_ADMIN | 启用常规复制控制。级别:全局。 |
RESOURCE_GROUP_ADMIN | 启用资源组管理。级别:全局。 |
RESOURCE_GROUP_USER | 启用资源组管理。级别:全局。 |
ROLE_ADMIN | 启用授予或撤销角色,使用WITH ADMIN OPTION。级别:全局。 |
SESSION_VARIABLES_ADMIN | 启用设置受限会话系统变量。级别:全局。 |
SET_USER_ID | 启用设置非自身DEFINER值。级别:全局。 |
SHOW_ROUTINE | 启用访问存储过程定义。级别:全局。 |
SKIP_QUERY_REWRITE | 不重写此用户执行的查询。级别:全局。 |
SYSTEM_USER | 指定帐户为系统帐户。级别:全局。 |
SYSTEM_VARIABLES_ADMIN | 启用修改或持久化全局系统变量。级别:全局。 |
TABLE_ENCRYPTION_ADMIN | 启用覆盖默认加密设置。级别:全局。 |
TELEMETRY_LOG_ADMIN | 启用在 AWS 上配置 MySQL HeatWave 的遥测日志。级别:全局。 |
TP_CONNECTION_ADMIN | 启用线程池连接管理。级别:全局。 |
VERSION_TOKEN_ADMIN | 启用版本令牌函数的使用。级别:全局。 |
XA_RECOVER_ADMIN | 启用XA RECOVER执行。级别:全局。 |
| 权限 | 意义和可授权级别 |
触发器与表关联。要创建或删除触发器,必须具有表的TRIGGER权限,而不是触发器的权限。
在GRANT 语句中,ALL [PRIVILEGES] 或 PROXY 权限必须单独命名,不能与其他权限一起指定。ALL [PRIVILEGES] 代表在要授予权限的级别上可用的所有权限,但不包括GRANT OPTION 和 PROXY 权限。
MySQL 账户信息存储在 mysql 系统模式的表中。有关更多详细信息,请参阅 第 8.2 节“访问控制和账户管理” ,该节详细讨论了 mysql 系统模式和访问控制系统。
如果授权表包含包含大小写混合的数据库或表名的权限行,并且 lower_case_table_names 系统变量设置为非零值,则无法使用 REVOKE 来撤销这些权限。在这种情况下,需要直接操作授权表。(GRANT 在设置 lower_case_table_names 时不会创建这样的行,但在设置该变量之前可能已创建这样的行。lower_case_table_names 设置只能在服务器启动时配置。)
根据 ON 子句的语法,可以在几个级别授予权限。对于 REVOKE,相同的 ON 语法指定要移除的权限。
对于全局、数据库、表和例程级别,GRANT ALL 仅分配在您授予的级别存在的权限。例如,GRANT ALL ON *db_name*.* 是一个数据库级别的语句,因此不授予任何全局权限,如FILE。授予ALL 不会分配GRANT OPTION 或 PROXY 权限。
如果存在 object_type 子句,则当以下对象为表、存储函数或存储过程时,应指定为 TABLE、FUNCTION 或 PROCEDURE。
用户对数据库、表、列或例程拥有的权限形成逻辑OR的账户权限的逻辑和,包括全局级别。不可能通过在较低级别缺少该权限来否定在更高级别授予的权限。例如,此语句全局授予SELECT和INSERT权限:
GRANT SELECT, INSERT ON *.* TO u1;
全局授予的权限适用于所有数据库、表和列,即使在这些较低级别中没有授予。
从 MySQL 8.0.16 开始,如果启用了partial_revokes系统变量,可以显式拒绝在全局级别授予的权限:
GRANT SELECT, INSERT, UPDATE ON *.* TO u1;
REVOKE INSERT, UPDATE ON db1.* FROM u1;
前述语句的结果是,SELECT全局适用于所有表,而INSERT和UPDATE全局适用,除了db1中的表。对db1的账户访问是只读的。
权限检查过程的详细信息在第 8.2.7 节,“访问控制,阶段 2:请求验证”中介绍。
如果您为任何用户使用表、列或例程权限,服务器会检查所有用户的表、列和例程权限,这会稍微减慢 MySQL 的速度。同样,如果限制任何用户的查询、更新或连接次数,服务器必须监视这些值。
MySQL 允许您授予不存在的数据库或表的权限。对于表,要授予的权限必须包括CREATE权限。这种行为是有意设计的,旨在使数据库管理员能够为稍后创建的数据库或表准备用户账户和权限。
重要提示
当您删除数据库或表时,MySQL 不会自动撤销任何权限。但是,如果删除例程,则为该例程授予的任何例程级别权限将被撤销。
全局权限
全局权限是管理性的,或者适用于给定服务器上的所有数据库。要分配全局权限,请使用ON *.*语法:
GRANT ALL ON *.* TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON *.* TO 'someuser'@'somehost';
CREATE TABLESPACE、CREATE USER、FILE、PROCESS、RELOAD、REPLICATION CLIENT、REPLICATION SLAVE、SHOW DATABASES、SHUTDOWN和SUPER静态权限是管理权限,只能全局授予。
动态权限都是全局的,只能全局授予。
其他权限可以全局授予或在更具体的级别授予。
在全局级别授予的GRANT OPTION的影响对于静态和动态权限有所不同:
-
为任何静态全局权限授予的
GRANT OPTION适用于所有静态全局权限。 -
为任何动态权限授予的
GRANT OPTION仅适用于该动态权限。
在全局级别使用GRANT ALL将授予所有静态全局权限和所有当前注册的动态权限。在执行GRANT语句后注册的动态权限不会向任何帐户追溯授予。
MySQL 将全局权限存储在mysql.user系统表中。
数据库权限
数据库权限适用于给定数据库中的所有对象。要分配数据库级别的权限,请使用ON *db_name*.*语法:
GRANT ALL ON mydb.* TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON mydb.* TO 'someuser'@'somehost';
如果您使用ON *语法(而不是ON *.*),则权限将分配给默认数据库的数据库级别。如果没有默认数据库,则会出现错误。
CREATE、DROP、EVENT、GRANT OPTION、LOCK TABLES和REFERENCES权限可以在数据库级别指定。表或例程权限也可以在数据库级别指定,这样它们将适用于数据库中的所有表或例程。
MySQL 将数据库权限存储在mysql.db系统表中。
表权限
表权限适用于给定表中的所有列。要分配表级别的权限,请使用ON *db_name.tbl_name*语法:
GRANT ALL ON mydb.mytbl TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON mydb.mytbl TO 'someuser'@'somehost';
如果您指定*tbl_name而不是db_name.tbl_name,则该语句适用于默认数据库中的tbl_name*。如果没有默认数据库,则会出现错误。
表级别的*priv_type*值可以是ALTER、CREATE VIEW、CREATE、DELETE、DROP、GRANT OPTION、INDEX、INSERT、REFERENCES、SELECT、SHOW VIEW、TRIGGER和UPDATE。
表级权限适用于基本表和视图。它们不适用于使用CREATE TEMPORARY TABLE创建的表,即使表名匹配。有关TEMPORARY表权限的信息,请参见第 15.1.20.2 节,“CREATE TEMPORARY TABLE Statement”。
MySQL 将表权限存储在mysql.tables_priv系统表中。
列权限
列权限适用于给定表中的单个列。在列级别授予权限时,每个权限都必须跟随列或列,括在括号内。
GRANT SELECT (col1), INSERT (col1, col2) ON mydb.mytbl TO 'someuser'@'somehost';
在列级(即使用*column_list子句时)的priv_type*值可以是INSERT、REFERENCES、SELECT和UPDATE。
MySQL 将列权限存储在mysql.columns_priv系统表中。
存储例程权限
ALTER ROUTINE、CREATE ROUTINE、EXECUTE和GRANT OPTION权限适用于存储例程(过程和函数)。它们可以在全局和数据库级别授予。除了CREATE ROUTINE外,这些权限可以在单个例程的例程级别授予。
GRANT CREATE ROUTINE ON mydb.* TO 'someuser'@'somehost';
GRANT EXECUTE ON PROCEDURE mydb.myproc TO 'someuser'@'somehost';
例程级别的*priv_type*值可以是ALTER ROUTINE、EXECUTE和GRANT OPTION。CREATE ROUTINE不是例程级别的权限,因为您必须在全局或数据库级别具有权限才能首先创建例程。
MySQL 将例程级权限存储在mysql.procs_priv系统表中。
代理用户权限
PROXY 权限允许一个用户代表另一个用户。代理用户冒充或者取代被代理用户的身份;也就是说,它承担了被代理用户的权限。
GRANT PROXY ON 'localuser'@'localhost' TO 'externaluser'@'somehost';
当授予PROXY时,它必须是GRANT语句中唯一命名的权限,并且唯一允许的WITH选项是WITH GRANT OPTION。
代理需要代理用户通过插件进行身份验证,当代理用户连接时,插件将返回被代理用户的名称给服务器,并且代理用户必须具有被代理用户的PROXY权限。有关详细信息和示例,请参见第 8.2.19 节,“代理用户”。
MySQL 将代理权限存储在mysql.proxies_priv系统表中。
授予角色
没有ON子句的GRANT语法授予角色而不是单独的权限。角色是一组命名的权限集合;请参见第 8.2.10 节,“使用角色”。例如:
GRANT 'role1', 'role2' TO 'user1'@'localhost', 'user2'@'localhost';
每个要授予的角色必须存在,以及要授予的每个用户帐户或角色。从 MySQL 8.0.16 开始,无法将角色授予匿名用户。
授予角色并不会自动使角色处于活动状态。有关角色激活和停用的信息,请参见激活角色。
授予角色需要以下权限:
-
如果您拥有
ROLE_ADMIN权限(或已弃用的SUPER权限),则可以向用户或角色授予或撤销任何角色。 -
如果您使用包含
WITH ADMIN OPTION子句的GRANT语句授予了一个角色,那么您就能够将该角色授予其他用户或角色,或者从其他用户或角色中撤销该角色,只要在随后授予或撤销该角色时该角色处于活动状态。这包括使用WITH ADMIN OPTION本身的能力。 -
要授予具有
SYSTEM_USER权限的角色,您必须具有SYSTEM_USER权限。
可以使用GRANT创建循环引用。例如:
CREATE USER 'u1', 'u2';
CREATE ROLE 'r1', 'r2';
GRANT 'u1' TO 'u1'; -- simple loop: u1 => u1
GRANT 'r1' TO 'r1'; -- simple loop: r1 => r1
GRANT 'r2' TO 'u2';
GRANT 'u2' TO 'r2'; -- mixed user/role loop: u2 => r2 => u2
允许循环授权引用,但不会向受权用户添加新的权限或角色,因为用户或角色已经拥有其权限和角色。
AS 子句和权限限制
从 MySQL 8.0.16 开始,GRANT有一个AS *user* [WITH ROLE]子句,用于指定关于语句执行所使用的权限上下文的附加信息。这种语法在 SQL 级别可见,尽管其主要目的是通过在二进制日志中显示部分撤销者强加的授权限制,从而实现所有节点之间的统一复制。有关部分撤销的信息,请参见第 8.2.12 节,“使用部分撤销进行权限限制”。
当指定AS *user*子句时,语句执行将考虑与命名用户相关联的任何权限限制,包括WITH ROLE指定的所有角色(如果存在)。结果是,实际授予的权限可能相对于指定的权限有所减少。
这些条件适用于AS *user*子句:
-
当命名的*
user*具有权限限制时,AS才会生效(这意味着partial_revokes系统变量已启用)。 -
如果给定了
WITH ROLE,则必须将所有命名的角色授予命名的*user*。 -
命名的*
user*应该是一个 MySQL 帐户,指定为'*user_name*'@'*host_name*',CURRENT_USER,或CURRENT_USER()。当前用户可以与WITH ROLE一起命名,以便执行用户希望GRANT以应用一组在当前会话中活动的角色不同的角色执行。 -
AS不能用于获取执行GRANT语句的用户不具备的权限。执行用户必须至少具有要授予的权限,但AS子句只能限制授予的权限,而不能提升它们。 -
关于要授予的权限,
AS不能指定一个比执行GRANT语句的用户/角色组合拥有更多权限(更少限制)的用户。AS用户/角色组合可以拥有比执行用户更多的权限,但只有在语句不授予这些额外权限时才可以。 -
AS仅支持授予全局权限(ON *.*)。 -
AS不支持PROXY授权。
以下示例说明了AS子句的效果。创建一个具有一些全局权限以及对这些权限的限制的用户u1:
CREATE USER u1;
GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
REVOKE INSERT, UPDATE ON schema1.* FROM u1;
REVOKE SELECT ON schema2.* FROM u1;
同时创建一个角色r1,解除一些权限限制并将该角色授予u1:
CREATE ROLE r1;
GRANT INSERT ON schema1.* TO r1;
GRANT SELECT ON schema2.* TO r1;
GRANT r1 TO u1;
现在,使用一个没有自己权限限制的帐户,向多个用户授予相同的全局权限集,但每个用户都受AS子句施加的不同限制,并检查实际授予了哪些权限。
-
这里的
GRANT语句没有AS子句,因此授予的权限正是指定的那些:mysql> CREATE USER u2; mysql> GRANT SELECT, INSERT, UPDATE ON *.* TO u2; mysql> SHOW GRANTS FOR u2; +-------------------------------------------------+ | Grants for u2@% | +-------------------------------------------------+ | GRANT SELECT, INSERT, UPDATE ON *.* TO `u2`@`%` | +-------------------------------------------------+ -
这里的
GRANT语句有一个AS子句,因此授予的权限是指定的那些,但应用了来自u1的限制:mysql> CREATE USER u3; mysql> GRANT SELECT, INSERT, UPDATE ON *.* TO u3 AS u1; mysql> SHOW GRANTS FOR u3; +----------------------------------------------------+ | Grants for u3@% | +----------------------------------------------------+ | GRANT SELECT, INSERT, UPDATE ON *.* TO `u3`@`%` | | REVOKE INSERT, UPDATE ON `schema1`.* FROM `u3`@`%` | | REVOKE SELECT ON `schema2`.* FROM `u3`@`%` | +----------------------------------------------------+如前所述,
AS子句只能添加权限限制;它不能提升权限。因此,尽管u1具有DELETE权限,但由于语句没有指定授予DELETE,所以这不包括在授予的权限中。 -
这里的
GRANT语句的AS子句使角色r1对u1生效。该角色解除了u1的一些限制。因此,授予的权限有一些限制,但不像前一个GRANT语句那样多:mysql> CREATE USER u4; mysql> GRANT SELECT, INSERT, UPDATE ON *.* TO u4 AS u1 WITH ROLE r1; mysql> SHOW GRANTS FOR u4; +-------------------------------------------------+ | Grants for u4@% | +-------------------------------------------------+ | GRANT SELECT, INSERT, UPDATE ON *.* TO `u4`@`%` | | REVOKE UPDATE ON `schema1`.* FROM `u4`@`%` | +-------------------------------------------------+
如果一个GRANT语句包括一个AS *user*子句,则执行该语句的用户的权限限制将被忽略(而不是像在没有AS子句的情况下那样应用)。
其他帐户特征
可选的WITH子句用于使用户能够向其他用户授予权限。WITH GRANT OPTION子句使用户能够将用户在指定权限级别拥有的任何权限授予其他用户。
要向一个帐户授予GRANT OPTION权限,而不改变其它权限,可以这样做:
GRANT USAGE ON *.* TO 'someuser'@'somehost' WITH GRANT OPTION;
谨慎授予GRANT OPTION权限,因为两个具有不同权限的用户可能能够结合权限!
你不能授予另一个用户你自己没有的权限;GRANT OPTION权限使你只能分配你自己拥有的权限。
请注意,当您在特定权限级别授予用户 GRANT OPTION 权限时,用户拥有的(或将来可能被授予的)该级别的任何权限也可以被该用户授予其他用户。假设您在数据库上授予用户 INSERT 权限。然后在数据库上授予 SELECT 权限并指定 WITH GRANT OPTION,那么该用户不仅可以给其他用户 SELECT 权限,还可以给予 INSERT。如果您然后在数据库上授予用户 UPDATE 权限,该用户可以授予 INSERT、SELECT 和 UPDATE。
对于非管理员用户,不应该在全局或 mysql 系统模式中授予 ALTER 权限。如果这样做,用户可以尝试通过重命名表来破坏权限系统!
有关与特定权限相关的安全风险的更多信息,请参阅 Section 8.2.2, “Privileges Provided by MySQL”。
MySQL 和标准 SQL 版本的 GRANT
MySQL 和标准 SQL 版本的 GRANT 之间最大的区别是:
-
MySQL 将权限与主机名和用户名的组合关联起来,而不仅仅是用户名。
-
标准 SQL 没有全局或数据库级别的权限,也不支持 MySQL 支持的所有权限类型。
-
MySQL 不支持标准 SQL 的
UNDER权限。 -
标准 SQL 权限以分层方式结构化。如果您移除一个用户,该用户被授予的所有权限都将被撤销。如果您在 MySQL 中使用
DROP USER也是如此。请参阅 Section 15.7.1.5, “DROP USER Statement”。 -
在标准 SQL 中,当您删除一个表时,该表的所有权限都将被撤销。在标准 SQL 中,当您撤销一个权限时,基于该权限授予的所有权限也将被撤销。在 MySQL 中,权限可以通过
DROP USER或REVOKE语句来撤销。 -
在 MySQL 中,可以仅对表中的某些列拥有
INSERT权限。在这种情况下,只要您为拥有INSERT权限的列插入值,您仍然可以在表上执行INSERT语句。如果严格 SQL 模式未启用,则省略的列将设置为它们的隐式默认值。在严格模式下,如果任何省略的列没有默认值,则该语句将被拒绝。(标准 SQL 要求您对所有列都拥有INSERT权限。)有关严格 SQL 模式和隐式默认值的信息,请参见第 7.1.11 节,“服务器 SQL 模式”和第 13.6 节,“数据类型默认值”。