MySQL8 中文参考(二十四) mysql8.025

MySQL8 中文参考(二十四) 原文:docs.oracle.com/javase/tutorial/reallybigindex.html 8.2 访问控制和账户管理 原文:dev.mysql.com/doc

原文:docs.oracle.com/javase/tutorial/reallybigindex.html

8.2 访问控制和账户管理

原文:dev.mysql.com/doc/refman/8.0/en/access-control.html

8.2.1 账户用户名和密码

8.2.2 MySQL提供的权限

8.2.3 批准表

8.2.4 指定账户名

8.2.5 指定角色名称

8.2.6 访问控制,第1 阶段:连接身份验证

8.2.7 访问控制,第2 阶段:需要身份验证

8.2.8 添加账户、分配权限、删除账户

8.2.9 预留账户

8.2.10 使用角色

8.2.11 账户类别

8.2.12 使用部分撤销有限权限

8.2.13 权限更改何时生效?

8.2.14 分配帐户密码

8.2.15 密码管理

8.2.16 服务器处理过期密码

8.2.17 可插入认证

8.2.18 多重身份验证

8.2.19 代理用户

8.2.20 账户锁定

8.2.21 设置账户资源限制

8.2.22 排除MySQL 连接问题

8.2.23 审核基于SQL 的帐户活动

MySQL 允许客户端用户创建帐户,以便他们连接到服务器并访问服务器管理的数据。 MySQL 权限系统的主要功能是对从特定主机连接的用户进行身份验证,并将其与数据库上的权限关联起来(SELECT、INSERT、UPDATE、DELETE 等)。其他功能包括授予管理操作权限。

为了控制谁可以连接,可以为每个帐户分配凭据,例如密码。 MySQL 帐户用户界面包括CREATE USER、GRANT 和REVOKE 等SQL 语句。请参阅账户管理声明。

MySQL权限系统确保所有用户只能执行他们被允许执行的操作。当您作为用户连接到MySQL 服务器时,您的身份由您连接的主机和您指定的用户名确定。连接后,您可以提出请求,并根据您的身份和要执行的操作获得权限。

MySQL 在识别用户时会考虑主机名和用户名。这是因为没有理由假设特定用户名属于所有主机上的同一个人。例如,从office.example.com 连接的用户joe 不一定是从home.example.com 连接的用户joe。 MySQL 通过允许区分不同主机上具有相同名称的用户来解决这个问题。您可以向从office.example.com 连接的joe 授予一组连接权限,向从home.example 连接的joe 授予另一组连接权限。com 的一组连接权限。要查看特定帐户拥有哪些权限,请使用SHOW GRANTS 语句。例如:

显示“joe”@“office.example.com”的权限;

显示“joe”@“home.example.com”的权限;

在内部,服务器将权限信息存储在mysql系统数据库的权限表中。 MySQL服务器在启动时将这些表的内容读入内存,并根据权限表的内存副本做出访问控制决策。

当运行连接到服务器的客户端程序时,MySQL 访问控制涉及两个阶段。

第一阶段:服务器根据用户的身份以及用户是否可以通过输入正确的密码确认其身份来接受或拒绝连接。

第2 阶段:假设可以连接,服务器会检查发出的每个语句,以确定它是否有足够的权限来执行它。例如,当您尝试从数据库的表中选择一行或删除数据库中的表时,服务器会检查您是否对该表具有SELECT 权限或对该数据库具有DROP 权限。

有关每个阶段发生的情况的更多信息,请参阅第8.2.6 节“访问控制,第1 阶段:连接验证”和第8.2.7 节“访问控制,第2 阶段:请求验证”。有关帮助诊断与权限相关的问题的信息,请参阅解决连接到MySQL 的问题。

如果您在连接时更改了您的权限(由您自己或其他人更改),这些更改可能不会在您发出下一条语句时立即生效。有关服务器何时重新加载授权表的更多信息,请参阅权限更改何时生效。

有些事情无法使用MySQL 权限系统执行。

您不能明确拒绝用户的访问。也就是说,您不能显式匹配用户然后拒绝连接。

您不能指定用户有权在数据库中创建或删除表,但不能指定数据库本身。

该密码对该帐户全局有效。密码不能与特定对象(例如数据库、表或例程)绑定。

8.2.1 账户用户名和密码

原文:dev.mysql.com/doc/refman/8.0/en/user-names.html

MySQL将账户存储在mysql系统数据库的用户表中。帐户是根据用户名和用户可以连接到服务器的一个或多个客户端主机来定义的。有关用户表中的帐户表示,请参阅授权表。

帐户还可能包括身份验证凭据,例如密码。这些凭据由帐户身份验证插件处理。 MySQL 支持多种身份验证插件。有些使用内置身份验证方法,而另一些则使用外部身份验证方法启用身份验证。请参阅可插入身份验证。

MySQL 和操作系统使用用户名和密码的方式存在一些差异。

用户名。它用于MySQL 身份验证目的,与Windows 或Unix 上用于登录的用户名无关。在Unix 上,默认情况下,大多数MySQL 客户端都会尝试使用当前Unix 用户名作为MySQL 用户名进行登录,但这只是为了方便。客户端程序可以使用-u 或–user 选项指定任何用户名,因此可以轻松覆盖默认设置。这意味着任何人都可以尝试使用任何用户名连接到您的服务器,因此除非所有MySQL 帐户都有密码,否则您的数据库无法以任何方式保持安全。任何人只要指定帐户的用户名(无需密码)即可成功连接到服务器。

MySQL 用户名的长度最多为32 个字符。您的操作系统的最大用户名长度可能会有所不同。

警告

MySQL 的用户名长度限制被硬编码到MySQL 服务器和客户端中,并且尝试通过更改MySQL 数据库中的表定义来解决该限制是行不通的。

除非通过第3 章“升级MySQL”中描述的过程,否则切勿更改mysql 数据库中的表结构。尝试以任何其他方式重新定义MySQL 系统表会导致未定义和不受支持的行为。服务器可以忽略由于这些更改而导致的格式错误的行。

为了对使用内置身份验证方法的帐户的客户端连接进行身份验证,服务器使用用户表中存储的密码。这些密码与用于登录操作系统的密码不同。用于登录Windows 或Unix 计算机的“外部”密码与用于访问该计算机上的MySQL 服务器的密码之间没有必然的联系。

当服务器使用其他插件对客户端进行身份验证时,插件实现的身份验证方法可能会也可能不会使用用户表中存储的密码。在这种情况下,也可以使用外部密码对MySQL 服务器进行身份验证。

存储在用户表中的密码使用插件特定的算法进行加密。

如果您的用户名和密码仅包含ASCII 字符,则无论字符集设置如何,您都可以连接到服务器。要在用户名或密码包含非ASCII 字符时启用连接,客户端应用程序必须使用MYSQL_SET_CHARSET_NAME 选项和适当的字符集名称作为参数来调用mysql_options() C API 函数。这将导致使用指定的字符集进行身份验证。否则,除非服务器的默认字符集与认证默认编码相同,否则认证将失败。

标准MySQL 客户端程序支持–default-character-set 选项。这将调用mysql_options(),如上所示。此外,还支持字符集的自动检测,如“连接字符集和排序规则”中所述。对于不基于C API 的连接器,可以提供类似于mysql_options() 的等效选项以供使用。请参阅连接器文档。

上述注意事项不适用于ucs2、utf16 和utf32,并且这些字符集不允许作为客户端字符集。

MySQL 安装过程会使用初始root 帐户填充身份验证表,如保护初始MySQL 帐户中所述。它还描述了如何为此帐户分配密码。然后,您通常可以使用CREATE USER、DROP USER、GRANT 和REVOKE 等语句来设置、修改和删除MySQL 帐户。请参阅添加帐户、分配权限以及删除帐户和帐户管理语句。

要使用命令行客户端连接到MySQL 服务器,请指定用户名和密码选项,具体取决于您使用的帐户:

$ mysql –user=finley –password *db_name*

如果使用短选项,则命令为:

$ mysql -u finley -p *数据库名称*

如果在命令行上省略–password 或-p 选项后面的密码值(如上所述),客户端将提示输入密码。或者,您可以在命令行上指定密码。

$ mysql –user=finley –password=*密码* *db_name*

$ mysql -u finley -p*密码* *数据库名称*

使用-p 选项时,-p 和下一个密码值之间不能有空格。

在命令行上指定密码应该被认为是不安全的。有关密码安全性,请参阅最终用户指南。为了避免在命令行中输入密码,您可以使用选项文件或登录密码文件。请参见第6.2.2.2节“使用选项文件”和第6.6.7节“mysql_config_editor – MySQL配置实用程序”。

有关指定用户名、密码和其他连接参数的更多信息,请参阅使用命令选项连接到MySQL 服务器。

8.2.2 MySQL 提供的权限

原文:dev.mysql.com/doc/refman/8.0/en/privileges-provided.html

授予MySQL 帐户的权限决定了该帐户可以执行的操作。 MySQL 权限根据其应用的上下文和操作级别而有所不同。

管理权限允许用户管理MySQL 服务器操作。这些权限是全局的,因为它们不特定于特定数据库。

数据库权限适用于数据库及其中的所有对象。这些权限可以针对特定数据库或全局授予,以便它们适用于所有数据库。

对数据库对象(例如表、索引、视图和存储过程)的权限可以授予数据库中的特定对象、数据库中特定类型的所有对象(例如数据库中的所有表)或所有对象. 可以在全球范围内授予。特定类型的所有对象。

权限也可以是静态的(内置于服务器中)或动态的(在运行时定义)。权限是静态还是动态会影响是否可以向用户帐户和角色授予权限。有关静态权限和动态权限之间的差异的信息,请参阅静态权限和动态权限。

有关帐户权限的信息存储在mysql 系统数据库的权限表中。有关这些表的结构和内容的说明,请参阅授权表。 MySQL服务器在启动时将权限表的内容读取到内存中,并在第8.2.13节“权限更改何时生效”中描述的条件下重新加载它们。服务器根据授权表的内存副本做出访问控制决策。

重要的

某些MySQL 版本会更改授权表以添加新的权限或功能。为了确保您可以利用新功能,请在每次升级MySQL 时将授权表更新为当前结构。请参阅第3 章“升级MySQL”。

以下部分总结了可用权限,提供每个权限的更详细说明,并提供使用指南。

可用权限概述

静态权限解释

动态权限解释

许可指南

静态和动态权限

将您的帐户从SUPER 迁移到动态权限

可用权限摘要

下表显示了GRANT 和REVOKE 语句中使用的静态权限名称、与授权表中每个权限关联的列名称以及权限应用的上下文。

表8.2 GRANT 和REVOKE 允许的静态权限

授予表列上下文ALL [PRIVILEGES] “所有权限”的同义词服务器管理ALTERAlter_priv 表ALTER ROUTINEAlter_routine_priv 存储过程CREATECreate_priv 数据库、表或索引CREATE ROLECreate_role_priv 服务器管理CREATE ROUTINECreate_routine_priv 存储过程CREATE TABLESPACECreate_tablespace_priv 服务器管理CRE ATE TEMPORARY TABLE SCre ate_tmp_ table_priv 表创建USERCreate_user_priv 服务器管理CREATE VIEWCreate_view_priv 查看DELETEDelete_priv 表DROPDrop_priv 数据库、表或视图DROP ROLEDrop_role_priv 服务器管理EVENTEvent_priv 数据库EXECUTEExecute_priv 存储过程FILEFile_priv 服务器主机文件访问GRANT OPTIONGrant_priv 数据库、表或视图存储过程INDEXIndex_priv 表INSERTInsert_priv 表或列TABLESlock_ table_priv 数据库PROCESSProcess _priv服务器管理PROX YView proxies_priv 表服务器管理REFERENCESReferences_priv 数据库或表RELOADReload_priv 服务器管理REPLICATION CLIENTRepl_client_priv 服务器管理REPLICATION SLAVERepl_slave_priv 服务器管理SELECTSelect_priv 表或列SHOW DATABASESShow_db_priv 服务器管理SHOW VIEWShow_view_priv 查看SHUTDOWN Shutdown_priv 服务器管理SUPERSuper_priv 服务器管理TRIGGERTrigger_priv 表UPDATEUpdate_priv 表同义词或列USAGE \”服务器管理的PrivilegeGrant 表中的“无授予”ColumnContext

下表显示了GRANT 和REVOKE 语句中使用的动态权限名称以及权限应用的上下文。

表8.3 GRANT 和REVOKE 允许的动态权限

PrivilegeContextAPPLICATION_PASSWORD_ADMIN 双密码管理AUDIT_ABORT_EXEMPT 允许审核日志过滤器阻止查询AUDIT_ADMIN 审核日志管理AUTHENTICATION_POLICY_ADMIN 身份验证管理BACKUP_ADMIN 备份管理BINLOG_ADMIN 备份和复制管理BINLOG_ENCRYPTION_ADMIN 备份和复制管理CLONE_AD MIN 克隆管理CONNECTION_ADMIN 服务器管理E NCRYPTION_KEY_ AD MIN 服务器管理FIREWALL_ADMIN 防火墙管理FIREWALL_EXEMPT 防火墙管理FIREWALL_USER 防火墙管理FLUSH_OPTIMIZER_COSTS 服务器管理FLUSH_STATUS 服务器管理FLUSH_TABLES 服务器管理FLUSH_USER_RESOURCES 服务器管理GROUP_REPLICATION_ADMIN 复制管理GROUP_REPLICATION_STREAM 复制管理INNODB_REDO_LOG_ARCHIVE RE DO 日志存档管理INNODB_REDO_LOG_ENABLE REDO 日志管理MIN 服务器管理NDB _STORED_USERNDB 集群PASSWORDLESS_USER_ADMIN 身份验证管理PERSIST_RO_VARIABLES_ADMIN 服务器管理REPLICATION_APPLIER PRIVILEGE_CHECKS_USERREPLICATION_SLAVE_ADMIN 复制通道管理复制RESOURCE_GROUP_ADMIN资源组管理RESOURCE_GROUP_USER 资源组管理ROLE_ADMIN 服务器管理SENSITIVE_VARIABLES_OBSERVER 服务器管理SESSION_VARIABLES_ADMIN 服务器管理SET_USER_ID 服务器管理SHOW_ROUTINE 服务器管理SKIP_QUERY_REWRITE 服务器管理SYSTEM_USER 服务器管理SYSTEM_VARIABLES_ ADMIN 服务器管理TABLE_ENCRYPTION_ ADMIN 服务器管理TELEMETRY_LOG_ADMIN Tele Me AWS 上的MySQL HeatWave 的指标日志管理TP_CONNECTION_ADMIN 线程池VERSION_TOKEN_ADMIN服务器管理XA_RECOVER_ADMIN 服务器管理权限上下文管理

静态权限描述

静态权限内置于服务器中,这与在运行时定义的动态权限不同。以下列表描述了MySQL 中每个静态权限的可用性。

某些SQL 语句可能具有比此处显示的更具体的权限要求。如果是这种情况,将在相关声明的描述中提供详细信息。

一切,所有特权

这些权限标识符是“特定权限级别可用的所有权限”的简写(不包括GRANT OPTION)。例如,在全局或表级别授予ALL 将授予所有全局权限或所有表级别权限。

改变

允许您使用ALTER TABLE 语句更改表的结构。 ALTER TABLE 还需要CREATE 和INSERT 权限。要重命名表,您需要对旧表具有ALTER 和DROP 权限,以及对新表具有CREATE 和INSERT 权限。

改变你的日常生活

允许修改或删除存储例程(存储过程和函数)的语句。对例程定义之外的例程属性的访问权限也被授予已授予权限的范围内的例程,以及非例程DEFINER 用户的用户的例程。

创造

允许创建新数据库和表的语句。

创建角色

允许使用CREATE ROLE 语句。 (CREATE USER 权限还允许使用CREATE ROLE 语句。)请参阅“使用角色”。

CREATE ROLE 和DROP ROLE 权限不如CREATE USER 强大,因为它们只能用于创建和删除帐户。它们不能用于更改帐户属性或重命名帐户(例如CREATE USER)。请参阅用户和角色兼容性。

创建例程

允许创建存储例程(存储过程和存储函数)的语句。对于授予权限范围内的例程以及用户名不是Routine DEFINER 的例程,您还可以访问例程定义以外的例程属性。

创建表空间

允许创建、更改或删除表空间和日志文件组的语句。

创建临时表

允许您使用CREATE TEMPORARY TABLE 语句创建临时表。

PROCESS 权限还允许使用SHOW ENGINE 语句访问INFORMATION_SCHEMA InnoDB 表(名称以INNODB_ 开头的表)和INFORMATION_SCHEMA FILES 表(从MySQL 8.0.21 开始)。

代理人

允许一个用户冒充或成为另一用户。请参阅代理用户。

参考

创建外键约束需要父表的REFERENCES 权限。

ELOAD
RELOAD使以下操作生效:

使用FLUSH语句。
使用mysqladmin命令等同于FLUSH操作:flush-hosts,flush-logs,flush-privileges,flush-status,flush-tables,flush-threads,refresh和reload。
reload命令告诉服务器重新加载授权表到内存中。flush-privileges是reload的同义词。refresh命令关闭并重新打开日志文件并刷新所有表。其他flush-*xxx*命令执行类似于refresh的功能,但更具体,可能在某些情况下更可取。例如,如果要刷新日志文件,flush-logs比refresh更好。
使用mysqldump选项执行各种FLUSH操作:–flush-logs和–master-data。
使用RESET MASTER和RESET REPLICA(或在 MySQL 8.0.22 之前,RESET SLAVE)语句。
REPLICATION CLIENT
允许使用SHOW MASTER STATUS、SHOW REPLICA STATUS和SHOW BINARY LOGS语句。
复制从服务器
允许帐户请求在复制源服务器上对数据库进行的更新,使用SHOW REPLICAS(或在 MySQL 8.0.22 之前,SHOW SLAVE HOSTS)、SHOW RELAYLOG EVENTS和SHOW BINLOG EVENTS语句。还需要此权限才能使用mysqlbinlog选项–read-from-remote-server(-R)、–read-from-remote-source和–read-from-remote-master。将此权限授予由副本用于连接到当前服务器作为其复制源服务器的帐户。
SELECT
允许从数据库中选择表中的行。只有当SELECT语句实际访问表时,才需要SELECT权限。一些SELECT语句不访问表,可以在没有任何数据库权限的情况下执行。例如,您可以使用SELECT作为一个简单的计算器来评估不涉及表的表达式:
SELECT 1+1;
SELECT PI()*2;
还需要SELECT权限用于读取列值的其他语句。例如,在UPDATE语句中,需要为在*col_name=expr*赋值右侧引用的列或在DELETE或UPDATE语句的WHERE子句中命名的列。
用于EXPLAIN中使用的表或视图需要SELECT权限,包括视图定义中的任何基础表。
显示数据库
通过发出SHOW DATABASE语句,使账户能够查看数据库名称。没有此权限的账户只能看到他们拥有某些权限的数据库,并且如果服务器是使用–skip-show-database选项启动的,则根本无法使用该语句。
注意
因为任何静态全局权限被视为所有数据库的权限,任何静态全局权限使用户可以使用SHOW DATABASES或通过检查INFORMATION_SCHEMA的SCHEMATA表来查看所有数据库名称,除了通过部分撤销在数据库级别限制的数据库。
SHOW VIEW
允许使用SHOW CREATE VIEW语句。此权限也适用于与EXPLAIN一起使用的视图。
SHUTDOWN
允许使用SHUTDOWN和RESTART语句,mysqladmin shutdown命令,以及mysql_shutdown() C API 函数。
SUPER
SUPER是一个强大且影响深远的权限,不应轻易授予。如果一个账户只需要执行SUPER操作的子集,可能可以通过代替授予一个或多个动态权限来实现所需的权限集,每个动态权限都提供更有限的功能。请参阅动态权限描述。
注意
SUPER已被弃用,您应该期望它在将来的 MySQL 版本中被移除。请参阅从 SUPER 迁移到动态权限的账户迁移。
SUPER影响以下操作和服务器行为:

允许在运行时更改系统变量:

允许对全局系统变量进行服务器配置更改,使用SET GLOBAL和SET PERSIST。
相应的动态权限是SYSTEM_VARIABLES_ADMIN。
允许设置需要特殊权限的受限会话系统变量。
对应的动态特权是SESSION_VARIABLES_ADMIN。
参见 Section 7.1.9.1,“系统变量特权”。
启用对全局事务特性的更改(参见 Section 15.3.7,“SET TRANSACTION 语句”)。
对应的动态特权是SYSTEM_VARIABLES_ADMIN。
启用帐户启动和停止复制,包括组复制。
对于常规复制,对应的动态特权是REPLICATION_SLAVE_ADMIN,对于组复制是GROUP_REPLICATION_ADMIN。
启用使用CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)、CHANGE MASTER TO语句(在 MySQL 8.0.23 之前)和CHANGE REPLICATION FILTER语句。
对应的动态特权是REPLICATION_SLAVE_ADMIN。
通过PURGE BINARY LOGS和BINLOG语句实现二进制日志控制。
对应的动态特权是BINLOG_ADMIN。
启用在执行视图或存储程序时设置有效授权 ID。拥有此特权的用户可以在视图或存储程序的DEFINER属性中指定任何帐户。
对应的动态特权是SET_USER_ID。
启用使用CREATE SERVER、ALTER SERVER和DROP SERVER语句。
启用mysqladmin debug命令的使用。
启用InnoDB加密密钥轮换。
对应的动态特权是ENCRYPTION_KEY_ADMIN。
启用执行版本令牌函数。
对应的动态特权是VERSION_TOKEN_ADMIN。
启用授予和撤销角色,使用GRANT语句的WITH ADMIN OPTION子句,以及ROLES_GRAPHML()函数结果中的非空<graphml>元素内容。
相应的动态特权是ROLE_ADMIN。
允许控制不允许非SUPER账户的客户端连接:

允许使用KILL语句或mysqladmin kill命令终止属于其他账户的线程。(一个账户始终可以终止自己的线程。)
当SUPER客户端连接时,服务器不执行init_connect系统变量内容。
即使达到由max_connections系统变量配置的连接限制,服务器也会接受来自SUPER客户端的一个连接。
处于离线模式(启用offline_mode)的服务器不会在下一个客户端请求时终止SUPER客户端连接,并接受来自SUPER客户端的新连接。
当read_only系统变量启用时,可以执行更新操作。这适用于显式表更新,以及使用诸如GRANT和REVOKE等更新表的账户管理语句。
前述连接控制操作对应的动态特权是CONNECTION_ADMIN。
如果启用了二进制日志记录,您可能还需要SUPER特权来创建或更改存储函数,如 Section 27.7, “Stored Program Binary Logging”中所述。
TRIGGER
启用触发器操作。您必须对表具有此特权才能为该表创建、删除、执行或显示触发器。
当触发器被激活(由具有执行INSERT、UPDATE或DELETE语句权限的用户激活,与触发器相关联的表),触发器执行要求定义触发器的用户仍然对表具有TRIGGER特权。
UPDATE
允许更新数据库中表中的行。
USAGE
此特权说明符代表“无特权”。它在全局级别与GRANT一起使用,用于指定诸如WITH GRANT OPTION之类的子句,而不在特权列表中命名特定帐户特权。SHOW GRANTS显示USAGE以指示帐户在特权级别上没有特权。

动态特权描述

动态特权在运行时定义,与内置于服务器中的静态特权相对。以下列表描述了 MySQL 中每个可用的动态特权。

大多数动态特权在服务器启动时定义。其他特权由特定组件或插件定义,如特权描述中所示。在这种情况下,除非启用定义它的组件或插件,否则该特权不可用。

特定的 SQL 语句可能具有比此处指示的更具体的特权要求。如果是这样,相关语句的描述提供详细信息。

APPLICATION_PASSWORD_ADMIN(在 MySQL 8.0.14 中添加)
对于双密码功能,此特权允许使用RETAIN CURRENT PASSWORD和DISCARD OLD PASSWORD子句,适用于您自己的帐户的ALTER USER和SET PASSWORD语句。大多数用户只需要一个密码,因此需要此特权来操作自己的次要密码。
如果要允许帐户操作所有帐户的次要密码,则应授予CREATE USER特权,而不是APPLICATION_PASSWORD_ADMIN。
有关双密码使用的更多信息,请参见第 8.2.15 节,“密码管理”。
AUDIT_ABORT_EXEMPT(在 MySQL 8.0.28 中添加)
允许在审计日志过滤器中由“中止”项目阻止的查询。此特权由audit_log插件定义;请参见第 8.4.5 节,“MySQL 企业审计”。
在 MySQL 8.0.28 或更高版本中创建的带有SYSTEM_USER权限的帐户在创建时会自动分配AUDIT_ABORT_EXEMPT权限。在进行 MySQL 8.0.28 或更高版本的升级过程中,如果没有现有帐户被分配该权限,则具有SYSTEM_USER权限的现有帐户也会被分配AUDIT_ABORT_EXEMPT权限。因此,具有SYSTEM_USER权限的帐户可用于在审核配置错误后恢复对系统的访问。
AUDIT_ADMIN
启用审核日志配置。此权限由audit_log插件定义;请参阅第 8.4.5 节,“MySQL 企业审计”。
BACKUP_ADMIN
启用执行LOCK INSTANCE FOR BACKUP语句和访问性能模式log_status表。
注意
除了BACKUP_ADMIN权限外,还需要对log_status表的SELECT权限才能访问。
在从早期版本升级到 MySQL 8.0 时,具有RELOAD权限的用户在执行就地升级时会自动被授予BACKUP_ADMIN权限。
AUTHENTICATION_POLICY_ADMIN(MySQL 8.0.27 中新增)
authentication_policy系统变量对CREATE USER和ALTER USER语句中的身份验证相关子句的使用施加了一定的约束。具有AUTHENTICATION_POLICY_ADMIN权限的用户不受这些约束的限制。(对于否则不允许的语句会发出警告。)
有关authentication_policy强加的约束的详细信息,请参阅该变量的描述。
BINLOG_ADMIN
通过PURGE BINARY LOGS和BINLOG语句启用二进制日志控制。
BINLOG_ENCRYPTION_ADMIN
启用设置系统变量binlog_encryption,该变量激活或停用二进制日志文件和中继日志文件的加密。这种能力不是由BINLOG_ADMIN、SYSTEM_VARIABLES_ADMIN 或 SESSION_VARIABLES_ADMIN 权限提供的。相关的系统变量binlog_rotate_encryption_master_key_at_startup,在服务器重新启动时自动旋转二进制日志主密钥,不需要此权限。
CLONE_ADMIN
启用执行CLONE语句。包括BACKUP_ADMIN 和 SHUTDOWN 权限。
CONNECTION_ADMIN
启用使用KILL语句或mysqladmin kill 命令来终止属于其他账户的线程。 (一个账户始终可以终止自己的线程。)
启用设置与客户端连接相关的系统变量,或绕过与客户端连接相关的限制。从 MySQL 8.0.31 开始,需要CONNECTION_ADMIN 权限来激活 MySQL 服务器的离线模式,这是通过将offline_mode系统变量的值更改为ON来完成的。
CONNECTION_ADMIN 权限使具有该权限的管理员可以绕过这些系统变量的影响:

init_connect: 当CONNECTION_ADMIN 客户端连接时,服务器不会执行init_connect系统变量内容。
max_connections: 即使达到由max_connections系统变量配置的连接限制,服务器也会接受来自CONNECTION_ADMIN 客户端的一个连接。
offline_mode:处于离线模式的服务器(启用了offline_mode)不会在下一个客户端请求时终止CONNECTION_ADMIN客户端连接,并接受来自CONNECTION_ADMIN客户端的新连接。
read_only:即使启用了read_only系统变量,也可以执行来自CONNECTION_ADMIN客户端的更新。这适用于显式表更新,以及更新隐式更新表的账户管理语句,如GRANT和REVOKE。
Group Replication 组成员需要CONNECTION_ADMIN特权,以便在涉及的服务器中的一个处于离线模式时,Group Replication 连接不会被终止。如果使用 MySQL 通信堆栈(group_replication_communication_stack = MYSQL),没有此特权,处于离线模式的成员将被从组中驱逐。
ENCRYPTION_KEY_ADMIN
启用InnoDB加密密钥轮换。
FIREWALL_ADMIN
启用用户管理任何用户的防火墙规则。此特权由MYSQL_FIREWALL插件定义;参见第 8.4.7 节,“MySQL 企业防火墙”。
FIREWALL_EXEMPT(MySQL 8.0.27 中添加)
拥有此特权的用户不受防火墙限制。此特权由MYSQL_FIREWALL插件定义;参见第 8.4.7 节,“MySQL 企业防火墙”。
FIREWALL_USER
启用用户更新其自己的防火墙规则。此特权由MYSQL_FIREWALL插件定义;参见第 8.4.7 节,“MySQL 企业防火墙”。
FLUSH_OPTIMIZER_COSTS(MySQL 8.0.23 中添加)
启用FLUSH OPTIMIZER_COSTS语句的使用。
FLUSH_STATUS(MySQL 8.0.23 中添加)
启用FLUSH STATUS语句的使用。
FLUSH_TABLES(MySQL 8.0.23 中添加)
启用FLUSH TABLES语句的使用。
FLUSH_USER_RESOURCES(MySQL 8.0.23 中添加)
允许使用FLUSH USER_RESOURCES语句。
GROUP_REPLICATION_ADMIN
允许账户启动和停止组复制,使用START GROUP REPLICATION和STOP GROUP REPLICATION语句,更改group_replication_consistency系统变量的全局设置,并使用group_replication_set_write_concurrency()和group_replication_set_communication_protocol()函数。授予此权限给用于管理属于复制组的服务器的账户。
GROUP_REPLICATION_STREAM
允许用户账户用于建立组复制的组通信连接。当 MySQL 通信堆栈用于组复制时(group_replication_communication_stack=MYSQL),必须授予恢复用户此权限。
INNODB_REDO_LOG_ARCHIVE
允许账户激活和停用重做日志归档。
INNODB_REDO_LOG_ENABLE
允许使用ALTER INSTANCE {ENABLE|DISABLE} INNODB REDO_LOG语句启用或禁用重做日志。MySQL 8.0.21 中引入。
参见禁用重做日志。
MASKING_DICTIONARIES_ADMIN
允许账户使用masking_dictionary_term_add()和masking_dictionary_term_remove()组件函数添加和移除字典术语。账户还需要此动态权限使用masking_dictionary_remove()函数移除完整字典,该函数会移除mysql.masking_dictionaries表中与命名字典相关的所有术语。
请参阅 第 8.5 节,“MySQL 企业数据脱敏和去标识化”。
NDB_STORED_USER
使用户或角色及其权限能够在所有加入给定 NDB 集群的 NDB 启用的 MySQL 服务器之间共享和同步。此特权仅在启用 NDB 存储引擎时可用。
对给定用户或角色的权限更改或撤销会立即与所有连接的 MySQL 服务器(SQL 节点)同步。您应该注意,不能保证来自不同 SQL 节点的影响权限的多个语句以相同顺序在所有 SQL 节点上执行。因此,强烈建议所有用户管理都从一个指定的 SQL 节点进行。
NDB_STORED_USER 是一个全局特权,必须使用 ON *.* 进行授予或撤销。尝试为此特权设置任何其他范围将导致错误。这个特权可以授予大多数应用程序和管理用户,但不能授予系统保留帐户,如 mysql.session@localhost 或 mysql.infoschema@localhost。
被授予 NDB_STORED_USER 特权的用户存储在 NDB 中(因此被所有 SQL 节点共享),具有此特权的角色也是如此。仅仅被授予具有 NDB_STORED_USER 的角色的用户 不 存储在 NDB 中;每个 NDB 存储的用户必须显式授予该特权。
有关在 NDB 中如何工作的更详细信息,请参阅 第 25.6.13 节,“特权同步和 NDB_STORED_USER”。
NDB_STORED_USER 特权从 NDB 8.0.18 开始提供。
PASSWORDLESS_USER_ADMIN(在 MySQL 8.0.27 中添加)
此特权适用于无密码用户帐户:

对于帐户创建,执行 CREATE USER 创建无密码帐户的用户必须具有 PASSWORDLESS_USER_ADMIN 特权。
在复制环境中,PASSWORDLESS_USER_ADMIN 特权适用于复制用户,并允许为配置为无密码身份验证的用户帐户复制 ALTER USER … MODIFY 语句。
有关无密码身份验证的信息,请参阅 FIDO 无密码身份验证。
PERSIST_RO_VARIABLES_ADMIN
对于还具有SYSTEM_VARIABLES_ADMIN的用户,PERSIST_RO_VARIABLES_ADMIN允许使用SET PERSIST_ONLY将全局系统变量持久化到数据目录中的mysqld-auto.cnf选项文件中。此语句类似于SET PERSIST,但不修改运行时全局系统变量值。这使得SET PERSIST_ONLY适用于配置只能在服务器启动时设置的只读系统变量。
参见 第 7.1.9.1 节,“系统变量权限”。
REPLICATION_APPLIER
启用账户作为复制通道的PRIVILEGE_CHECKS_USER,并在mysqlbinlog输出中执行BINLOG语句。授予此权限给通过CHANGE REPLICATION SOURCE TO(从 MySQL 8.0.23 开始)或CHANGE MASTER TO(在 MySQL 8.0.23 之前)分配的账户,以为复制通道提供安全上下文,并处理这些通道上的复制错误。除了REPLICATION_APPLIER权限外,您还必须为账户授予执行复制通道接收的事务或包含在mysqlbinlog输出中的所需权限,例如更新受影响的表。有关更多信息,请参见 第 19.3.3 节,“复制权限检查”。
REPLICATION_SLAVE_ADMIN
允许帐户连接到复制源服务器,使用START REPLICA和STOP REPLICA语句启动和停止复制,并使用CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(在 MySQL 8.0.23 之前)以及CHANGE REPLICATION FILTER语句。授予此特权给由副本使用的帐户,以连接到当前服务器作为其复制源服务器。此特权不适用于组复制;对于组复制,请使用GROUP_REPLICATION_ADMIN。
RESOURCE_GROUP_ADMIN
允许资源组管理,包括创建、修改和删除资源组,以及将线程和语句分配给资源组。拥有此特权的用户可以执行与资源组相关的任何操作。
RESOURCE_GROUP_USER
允许将线程和语句分配给资源组。拥有此特权的用户可以使用SET RESOURCE GROUP语句和RESOURCE_GROUP优化提示。
ROLE_ADMIN
允许授予和撤销角色,使用GRANT语句的WITH ADMIN OPTION子句,以及ROLES_GRAPHML()函数结果中的非空<graphml>元素内容。需要设置mandatory_roles系统变量的值。
SENSITIVE_VARIABLES_OBSERVER(在 MySQL 8.0.29 中添加)
允许持有者查看性能模式表中敏感系统变量的值global_variables,session_variables,variables_by_thread,和persisted_variables,发出SELECT语句以返回它们的值,并在会话跟踪器中跟踪连接的更改。没有此权限的用户无法查看或跟踪这些系统变量的值。请参见持久化敏感系统变量。
SERVICE_CONNECTION_ADMIN
允许连接到仅允许管理连接的网络接口(参见第 7.1.12.1 节,“连接接口”)。
SESSION_VARIABLES_ADMIN(在 MySQL 8.0.14 中添加)
对于大多数系统变量,设置会话值不需要特殊权限,任何用户都可以执行以影响当前会话。对于一些系统变量,设置会话值可能会影响当前会话之外的效果,因此是一项受限操作。对于这些情况,SESSION_VARIABLES_ADMIN权限使用户能够设置会话值。
如果系统变量受限并需要特殊权限来设置会话值,则变量描述会指示该限制。例如包括binlog_format,sql_log_bin,和sql_log_off。
在 MySQL 8.0.14 之前,当添加了SESSION_VARIABLES_ADMIN时,受限会话系统变量只能由具有SYSTEM_VARIABLES_ADMIN或SUPER权限的用户设置。
SESSION_VARIABLES_ADMIN 特权是SYSTEM_VARIABLES_ADMIN 和 SUPER 特权的子集。拥有这些特权之一的用户也被允许设置受限制的会话变量,并且通过暗示具有SESSION_VARIABLES_ADMIN,无需显式授予SESSION_VARIABLES_ADMIN。
另请参阅第 7.1.9.1 节,“系统变量特权”。
SET_USER_ID
允许在执行视图或存储程序时设置有效的授权 ID。拥有此特权的用户可以将任何帐户指定为视图或存储程序的DEFINER属性。存储程序将以指定帐户的权限执行,因此请确保遵循第 27.6 节,“存储对象访问控制”中列出的风险最小化准则。
截至 MySQL 8.0.22,SET_USER_ID 还允许覆盖旨在防止(可能是无意的)导致存储对象变成孤立或导致当前孤立的存储对象被采用的安全检查。有关详细信息,请参阅孤立存储对象。
SHOW_ROUTINE(MySQL 8.0.20 中添加)
允许用户访问所有存储例程(存储过程和函数)的定义和属性,即使用户未被命名为例程的DEFINER。此访问权限包括:

信息模式ROUTINES表的内容。
SHOW CREATE FUNCTION 和 SHOW CREATE PROCEDURE 语句。
SHOW FUNCTION CODE 和 SHOW PROCEDURE CODE 语句。
SHOW FUNCTION STATUS 和 SHOW PROCEDURE STATUS 语句。
在 MySQL 8.0.20 之前,用户要访问未定义的例程的定义,用户必须拥有全局SELECT 权限,这是非常广泛的。从 8.0.20 开始,可以授予SHOW_ROUTINE 权限,这是一个范围更受限制的权限,允许访问例程定义。(也就是说,管理员可以从不需要的用户那里撤销全局SELECT 并授予SHOW_ROUTINE)。这使得一个账户可以备份存储例程而不需要广泛的权限。
SKIP_QUERY_REWRITE(MySQL 8.0.31 中添加)
拥有此权限的用户发出的查询不会被Rewriter插件重写(参见第 7.6.4 节,“Rewriter 查询重写插件”)。
此权限应授予发出不应被重写的管理或控制语句的用户,以及用于应用来自复制源的语句的PRIVILEGE_CHECKS_USER账户(参见第 19.3.3 节,“复制权限检查”)。
SYSTEM_USER(MySQL 8.0.16 中添加)
SYSTEM_USER 权限区分系统用户和普通用户:

拥有SYSTEM_USER 权限的用户是系统用户。
没有SYSTEM_USER 权限的用户是普通用户。
SYSTEM_USER 权限影响用户可以应用其它权限的账户,以及用户是否受到其他账户的保护:

系统用户可以修改系统账户和普通账户。也就是说,拥有在普通账户上执行特定操作的适当权限的用户,通过拥有SYSTEM_USER 权限也可以在系统账户上执行该操作。只有拥有适当权限的系统用户才能修改系统账户,普通用户无法修改。
拥有适当权限的普通用户可以修改普通账户,但不能修改系统账户。系统账户可以被拥有适当权限的系统用户和普通用户修改。
这也意味着,由拥有SYSTEM_USER 权限的用户创建的数据库对象不能被没有该权限的用户修改或删除。对于定义者拥有此权限的例程也适用。
更多信息,请参见第 8.2.11 节,“账户类别”。
由于SYSTEM_USER权限为系统帐户提供的修改保护不适用于具有对mysql系统模式特权的常规帐户,因此可以直接修改该模式中的授权表。为了完全保护,请不要向常规帐户授予mysql模式特权。请参见防止常规帐户操纵系统帐户。
如果使用了audit_log插件(参见第 8.4.5 节,“MySQL 企业审计”),从 MySQL 8.0.28 开始,具有SYSTEM_USER权限的帐户将自动被分配AUDIT_ABORT_EXEMPT权限,允许他们的查询即使在过滤器中配置了“中止”项目也能执行。具有SYSTEM_USER权限的帐户因此可用于在审计配置错误后恢复对系统的访问。
SYSTEM_VARIABLES_ADMIN
影响以下操作和服务器行为:

允许在运行时更改系统变量:

允许使用SET GLOBAL和SET PERSIST对全局系统变量进行服务器配置更改。
允许使用SET PERSIST_ONLY对全局系统变量进行服务器配置更改,如果用户还具有PERSIST_RO_VARIABLES_ADMIN权限。
允许设置需要特殊权限的受限会话系统变量。实际上,SYSTEM_VARIABLES_ADMIN意味着未明确授予SESSION_VARIABLES_ADMIN。
另请参阅第 7.1.9.1 节,“系统变量权限”。
允许更改全局事务特性(参见第 15.3.7 节,“SET TRANSACTION 语句”)。
TABLE_ENCRYPTION_ADMIN(在 MySQL 8.0.16 中添加)
当启用table_encryption_privilege_check时,允许用户覆盖默认加密设置;参见为模式和通用表空间定义加密默认值。
TELEMETRY_LOG_ADMIN
启用遥测日志配置。此特权由部署在 AWS 上的 MySQL HeatWave 的telemetry_log插件定义。
TP_CONNECTION_ADMIN
允许使用特权连接连接到服务器。当达到由thread_pool_max_transactions_limit定义的限制时,不允许新连接。特权连接忽略事务限制,并允许连接到服务器以增加事务限制、移除限制或终止运行中的事务。此特权不会默认授予任何用户。要建立特权连接,发起连接的用户必须具有TP_CONNECTION_ADMIN特权。
当达到由thread_pool_max_transactions_limit定义的限制时,特权连接可以执行语句并启动事务。特权连接被放置在Admin线程组中。参见特权连接。
VERSION_TOKEN_ADMIN
允许执行版本令牌函数。此特权由version_tokens插件定义;参见第 7.6.6 节,“版本令牌”。
XA_RECOVER_ADMIN
允许执行XA RECOVER语句;参见第 15.3.8.1 节,“XA 事务 SQL 语句”。
在 MySQL 8.0 之前,任何用户都可以执行 XA RECOVER 语句来发现未完成的准备好的 XA 事务的 XID 值,可能导致由非启动者执行提交或回滚 XA 事务。在 MySQL 8.0 中,XA RECOVER 仅允许拥有 XA_RECOVER_ADMIN 权限的用户执行,这个权限预期只授予有需要的管理用户。例如,如果 XA 应用程序崩溃并且需要找到应用程序启动的未完成事务以便回滚,那么可能会出现这种情况。这种权限要求阻止用户发现除自己之外的未完成准备好的 XA 事务的 XID 值。它不会影响 XA 事务的正常提交或回滚,因为启动它的用户知道它的 XID。

权限授予指南

为账户授予它所需的权限是一个好主意。在授予 FILE 和管理权限时应特别小心:

FILE 可以被滥用来读取 MySQL 服务器在服务器主机上可以读取的任何文件到数据库表中。这包括所有可读取的文件和服务器数据目录中的文件。然后可以使用 SELECT 访问该表,将其内容传输到客户端主机。
GRANT OPTION 允许用户将他们的权限授予其他用户。拥有不同权限并且具有 GRANT OPTION 权限的两个用户可以组合权限。
ALTER 可能被用于通过重命名表来破坏权限系统。
SHUTDOWN 可以被滥用来通过终止服务器来完全拒绝其他用户的服务。
PROCESS 可以用于查看当前执行语句的纯文本,包括设置或更改密码的语句。
SUPER 可以用于终止其他会话或更改服务器操作方式。
为 mysql 系统数据库本身授予的权限可以用于更改密码和其他访问权限信息:

密码被加密存储,因此恶意用户不能简单地读取它们以了解明文密码。但是,具有对 mysql.user 系统表 authentication_string 列的写入访问权限的用户可以更改账户的密码,然后使用该账户连接到 MySQL 服务器。
为 mysql 系统数据库授予的 INSERT 或 UPDATE 权限使用户能够添加权限或修改现有权限。
为 mysql 系统数据库的 DROP 允许用户删除权限表,甚至是数据库本身。

静态权限与动态权限

MySQL 支持静态和动态权限:

静态权限内置于服务器中。它们始终可供授予给用户帐户,并且无法注销。
动态权限可以在运行时注册和注销。这会影响它们的可用性:未注册的动态权限无法授予。

例如,SELECT 和 INSERT 权限是静态的,并且始终可用,而实现它的组件已启用时才会提供动态权限。

本节的其余部分描述了 MySQL 中动态权限的工作原理。讨论中使用术语“组件”,但同样适用于插件。

注意

服务器管理员应该了解哪些服务器组件定义了动态权限。对于 MySQL 发行版,定义动态权限的组件的文档描述了这些权限。

第三方组件也可能定义动态权限;管理员应该了解这些权限,并且不安装可能会与服务器操作发生冲突或危害的组件。例如,如果两个组件都定义了相同名称的权限,则一个组件会与另一个组件发生冲突。组件开发人员可以通过选择以组件名称为前缀的权限名称来减少此类情况发生的可能性。

服务器在内存中维护已注册的动态权限集。在服务器关闭时进行注销。

通常,定义动态权限的组件在安装时会注册它们,在初始化序列期间。当卸载时,组件不会注销其已注册的动态权限。(这是当前的做法,而不是要求。也就是说,组件可以,但不会在任何时候注销其注册的权限。)

尝试注册已经注册的动态权限不会出现警告或错误。考虑以下语句序列:

INSTALL COMPONENT \’my_component\’;
UNINSTALL COMPONENT \’my_component\’;
INSTALL COMPONENT \’my_component\’;

第一个 INSTALL COMPONENT 语句注册了组件 my_component 定义的任何权限,但 UNINSTALL COMPONENT 不会注销它们。对于第二个 INSTALL COMPONENT 语句,它注册的组件权限已经被发现已经注册,但不会出现警告或错误。

动态权限仅适用于全局级别。服务器在mysql.global_grants系统表中存储有关动态权限对用户帐户的当前分配的信息:

服务器在启动时自动注册global_grants中命名的权限(除非提供了–skip-grant-tables选项)。
GRANT和REVOKE语句修改global_grants的内容。
在global_grants中列出的动态权限分配是持久的。它们在服务器关闭时不会被移除。

示例:以下语句授予用户u1在副本上控制复制(包括组复制)和修改系统变量所需的权限:

GRANT REPLICATION_SLAVE_ADMIN, GROUP_REPLICATION_ADMIN, BINLOG_ADMIN
ON *.* TO \’u1\’@\’localhost\’;

授予的动态权限将出现在SHOW GRANTS语句和INFORMATION_SCHEMA USER_PRIVILEGES表的输出中。

对于GRANT和REVOKE在全局级别,任何未被识别为静态的命名权限将与当前注册的动态权限集合进行检查,如果找到则授予。否则,将发生错误以指示未知的权限标识符。

对于GRANT和REVOKE在全局级别,ALL [PRIVILEGES]的含义包括所有静态全局权限,以及当前注册的所有动态权限:

GRANT ALL 在全局级别授予所有静态全局权限和当前注册的所有动态权限。在执行GRANT语句后注册的动态权限不会追溯地授予任何帐户。
REVOKE ALL 在全局级别撤销所有授予的静态全局权限和所有授予的动态权限。

FLUSH PRIVILEGES语句读取global_grants表中的动态权限分配,并注册在那里找到的任何未注册的权限。

有关 MySQL Server 和 MySQL 发行版中包含的组件提供的动态权限的描述,请参见 Section 8.2.2, “MySQL 提供的权限”。

从 SUPER 迁移帐户到动态权限

在 MySQL 8.0 中,许多以前需要SUPER权限的操作也与更有限范围的动态权限相关联。(有关这些权限的描述,请参见第 8.2.2 节,“MySQL 提供的权限”。)每个这样的操作可以通过授予相关的动态权限而不是SUPER权限来允许给账户。这种变化通过使 DBA 避免授予SUPER权限并更紧密地调整用户权限以符合允许的操作来提高安全性。SUPER现已被弃用;预计它将在 MySQL 的未来版本中被移除。

当移除SUPER权限时,以前需要SUPER权限的操作将失败,除非被授予SUPER权限的账户迁移到适当的动态权限。使用以下说明来实现这一目标,以便在SUPER权限被移除之前账户已准备就绪:

执行此查询以识别被授予SUPER权限的账户:
SELECT GRANTEE FROM INFORMATION_SCHEMA.USER_PRIVILEGES
WHERE PRIVILEGE_TYPE = \’SUPER\’;
对于由上述查询确定的每个账户,确定其需要SUPER权限的操作。然后授予相应操作的动态权限,并撤销SUPER。
例如,如果\’u1\’@\’localhost\’需要SUPER权限用于二进制日志清除和系统变量修改,以下语句将对账户进行所需更改:
GRANT BINLOG_ADMIN, SYSTEM_VARIABLES_ADMIN ON *.* TO \’u1\’@\’localhost\’;
REVOKE SUPER ON *.* FROM \’u1\’@\’localhost\’;
在修改了所有适用账户之后,第一步中的INFORMATION_SCHEMA查询应产生一个空结果集。

8.2.3 授权表

原文:dev.mysql.com/doc/refman/8.0/en/grant-tables.html

mysql系统数据库包含几个授权表,其中包含有关用户账户和其持有的权限的信息。本节描述了这些表。有关系统数据库中其他表的信息,请参阅第 7.3 节,“mysql 系统模式”。

此处讨论了授权表的基本结构以及服务器在与客户端交互时如何使用其内容。然而,通常情况下不直接修改授权表。当您使用诸如CREATE USER, GRANT, 和 REVOKE等账户管理语句设置账户和控制每个账户可用权限时,修改是间接发生的。请参阅第 15.7.1 节,“账户管理语句”。当您使用这些语句执行账户操作时,服务器会代表您修改授权表。

注意

不鼓励直接使用诸如INSERT, UPDATE, 或 DELETE等语句直接修改授权表,这样做风险自负。服务器可以忽略由于这些修改导致的格式错误的行。

对于任何修改授权表的操作,服务器会检查表是否具有预期的结构,如果不是,则会产生错误。要将表更新为预期的结构,请执行 MySQL 升级过程。请参阅第三章,“升级 MySQL”。

授权表概述
用户和数据库授权表
tables_priv 和 columns_priv 授权表
procs_priv 授权表
proxies_priv 授权表
全局授权表
默认角色授权表
角色边缘授权表
密码历史授权表
授予表范围列属性
授予表权限列属性
授予表并发性

授予表概述

这些mysql数据库表包含授予信息:

user: 用户账户,静态全局权限和其他非权限列。
global_grants: 动态全局权限。
db: 数据库级权限。
tables_priv: 表级权限。
columns_priv: 列级权限。
procs_priv: 存储过程和函数权限。
proxies_priv: 代理用户权限。
default_roles: 默认用户角色。
role_edges: 角色子图的边缘。
password_history: 密码更改历史。

有关静态和动态全局权限之间的区别,请参阅静态与动态权限。

在 MySQL 8.0 中,授予表使用InnoDB存储引擎并且是事务性的。在 MySQL 8.0 之前,授予表使用MyISAM存储引擎并且是非事务性的。授予表存储引擎的更改使得伴随的账户管理语句的行为也发生了变化,例如CREATE USER或GRANT。以前,命名多个用户的账户管理语句可能对某些用户成功,对其他用户失败。现在,每个语句都是事务性的,要么对所有命名用户成功,要么回滚并且如果出现任何错误则不起作用。

每个授予表包含范围列和权限列:

范围列确定表中每行的范围;也就是说,行适用的上下文。例如,具有Host和User值为\’h1.example.net\’和\’bob\’的user表行适用于由指定用户名称为bob的客户端从主机h1.example.net进行的身份验证连接。类似地,具有Host,User和Db列值为\’h1.example.net\’,\’bob\’和\’reports\’的db表行适用于bob从主机h1.example.net连接以访问reports数据库。tables_priv和columns_priv表包含指示每行适用于哪些表或表/列组合的范围列。procs_priv范围列指示每行适用于的存储过程。
特权列指示表行授予哪些特权;也就是说,它允许执行哪些操作。服务器将各种授权表中的信息组合起来,形成用户特权的完整描述。第 8.2.7 节,“访问控制,第 2 阶段:请求验证”描述了这方面的规则。

此外,授权表可能包含用于除范围或特权评估之外的其他目的的列。

服务器使用授权表的方式如下:

user表的范围列确定是否拒绝或允许传入连接。对于允许的连接,在user表中授予的任何特权表示用户的静态全局特权。在此表中授予的任何特权都适用于所有服务器上的数据库。
注意
因为任何静态全局特权都被视为所有数据库的特权,任何静态全局特权都使用户能够通过SHOW DATABASES或通过检查INFORMATION_SCHEMA的SCHEMATA表来查看所有数据库名称,除了在数据库级别通过部分撤销限制的数据库。
global_grants表列出了对用户帐户分配的动态全局特权。对于每行,范围列确定具有特权列中命名的特权的用户。
db表的范围列确定哪些用户可以从哪些主机访问哪些数据库。特权列确定允许的操作。在数据库级别授予的特权适用于数据库及其所有对象,如表和存储程序。
tables_priv和columns_priv表类似于db表,但更加精细:它们适用于表和列级别,而不是数据库级别。在表级别授予的特权适用于表及其所有列。在列级别授予的特权仅适用于特定列。
procs_priv 表适用于存储例程(存储过程和函数)。在例程级别授予的权限仅适用于单个过程或函数。
proxies_priv 表指示哪些用户可以代表其他用户行事,以及用户是否可以向其他用户授予 PROXY 权限。
default_roles 和 role_edges 表包含有关角色关系的信息。
password_history 表保留先前选择的密码,以启用对密码重用的限制。请参阅 第 8.2.15 节,“密码管理”。

服务器在启动时将授予表的内容读入内存。您可以通过发出 FLUSH PRIVILEGES 语句或执行 mysqladmin flush-privileges 或 mysqladmin reload 命令来告诉它重新加载表。对授权表的更改将按照 第 8.2.13 节,“权限更改生效时间” 中指示的方式生效。

当您修改帐户时,最好验证您的更改是否产生预期效果。要检查给定帐户的权限,请使用 SHOW GRANTS 语句。例如,要确定授予具有用户名和主机名值为 bob 和 pc84.example.com 的帐户的权限,请使用此语句:

SHOW GRANTS FOR \’bob\’@\’pc84.example.com\’;

要显示帐户的非权限属性,请使用 SHOW CREATE USER:

SHOW CREATE USER \’bob\’@\’pc84.example.com\’;

用户和数据库授权表

服务器在访问控制的第一和第二阶段都使用 mysql 数据库中的 user 和 db 表(参见 第 8.2 节,“访问控制和账户管理”)。这里显示了 user 和 db 表中的列。

表 8.4 user 和 db 表列

表名userdb范围列HostHostUserDbUser权限列Select_privSelect_privInsert_privInsert_privUpdate_privUpdate_privDelete_privDelete_privIndex_privIndex_privAlter_privAlter_privCreate_privCreate_privDrop_privDrop_privGrant_privGrant_privCreate_view_privCreate_view_privShow_view_privShow_view_privCreate_routine_privCreate_routine_privAlter_routine_privAlter_routine_privExecute_privExecute_privTrigger_privTrigger_privEvent_privEvent_privCreate_tmp_table_privCreate_tmp_table_privLock_tables_privLock_tables_privReferences_privReferences_privReload_privShutdown_privProcess_privFile_privShow_db_privSuper_privRepl_slave_privRepl_client_privCreate_user_privCreate_tablespace_privCreate_role_privDrop_role_priv安全列ssl_typessl_cipherx509_issuerx509_subjectpluginauthentication_stringpassword_expiredpassword_last_changedpassword_lifetimeaccount_lockedPassword_reuse_historyPassword_reuse_timePassword_require_currentUser_attributes资源控制列max_questionsmax_updatesmax_connectionsmax_user_connections表名userdb
user表的plugin和authentication_string列存储身份验证插件和凭据信息。

服务器使用帐户行的plugin列中命名的插件来验证帐户的连接尝试。

plugin列必须非空。在启动时,以及在执行FLUSH PRIVILEGES时,服务器会检查user表行。对于任何plugin列为空的行,服务器会向错误日志写入以下警告:

[Warning] User entry \’*user_name*\’@\’*host_name*\’ has an empty plugin
value. The user will be ignored and no one can login with this user
anymore.

要为缺少插件的帐户分配插件,请使用ALTER USER语句。

password_expired列允许 DBA 过期帐户密码并要求用户重置密码。默认的password_expired值为\’N\’,但可以使用ALTER USER语句设置为\’Y\’。帐户密码过期后,在后续连接到服务器时,帐户执行的所有操作都会导致错误,直到用户发出ALTER USER语句以建立新的帐户密码。

注意

尽管可以通过将过期密码设置为当前值来“重置”过期密码,但最好根据良好的政策选择不同的密码。DBA 可以通过建立适当的密码重用策略来强制不重用。请参阅密码重用策略。

password_last_changed是一个TIMESTAMP列,指示密码上次更改的时间。该值仅对使用 MySQL 内置身份验证插件(mysql_native_password、sha256_password或caching_sha2_password)的帐户为非NULL。对于其他帐户,如使用外部身份验证系统进行身份验证的帐户,该值为NULL。

password_last_changed 由 CREATE USER、ALTER USER 和 SET PASSWORD 语句以及创建帐户或更改帐户密码的 GRANT 语句更新。

password_lifetime 指示帐户密码的生命周期,以天为单位。如果密码已超过其生命周期(使用 password_last_changed 列进行评估),当客户端使用该帐户连接时,服务器将视密码为已过期。大于零的 N 值表示密码必须每 N 天更改一次。值为 0 禁用自动密码过期。如果值为 NULL(默认值),则全局过期策略适用,由 default_password_lifetime 系统变量定义。

account_locked 指示帐户是否被锁定(参见第 8.2.20 节,“帐户锁定”)。

Password_reuse_history 是帐户的 PASSWORD HISTORY 选项的值,或者对于默认历史记录为 NULL。

Password_reuse_time 是帐户的 PASSWORD REUSE INTERVAL 选项的值,或者对于默认间隔为 NULL。

Password_require_current(MySQL 8.0.13 中新增)对应于帐户的 PASSWORD REQUIRE 选项的值,如下表所示。

表 8.5 允许的 Password_require_current 值

Password_require_current 值对应的 PASSWORD REQUIRE 选项\’Y\’PASSWORD REQUIRE CURRENT\’N\’PASSWORD REQUIRE CURRENT OPTIONALNULLPASSWORD REQUIRE CURRENT DEFAULT
User_attributes(MySQL 8.0.14 中新增)是一个以 JSON 格式存储帐户属性的列,这些属性未存储在其他列中。截至 MySQL 8.0.21,INFORMATION_SCHEMA 通过 USER_ATTRIBUTES 表公开这些属性。

User_attributes 列可能包含这些属性:

additional_password:次要密码,如果有的话。请参阅双密码支持。
Restrictions:限制列表,如果有的话。限制是通过部分撤销操作添加的。属性值是一个元素数组,每个元素都有 Database 和 Restrictions 键,指示受限数据库的名称和适用于其上的限制(参见第 8.2.12 节,“使用部分撤销进行权限限制”)。
Password_locking: 如果有的话,是关于失败登录跟踪和临时账户锁定的条件(参见失败登录跟踪和临时账户锁定)。Password_locking属性根据CREATE USER和ALTER USER语句的FAILED_LOGIN_ATTEMPTS和PASSWORD_LOCK_TIME选项进行更新。该属性值是一个哈希,其中包含failed_login_attempts和password_lock_time_days键,指示为该账户指定的选项值。如果某个键缺失,则其值隐式为 0。如果键值隐式或显式为 0,则相应的功能被禁用。此属性在 MySQL 8.0.19 中添加。
multi_factor_authentication: mysql.user系统表中的行具有一个plugin列,指示认证插件。对于单因素认证,该插件是唯一的认证因素。对于多因素认证的两因素或三因素形式,该插件对应于第一个认证因素,但必须为第二和第三因素存储额外信息。multi_factor_authentication属性保存了这些信息。此属性在 MySQL 8.0.27 中添加。
multi_factor_authentication值是一个数组,其中每个数组元素都是一个哈希,描述了使用以下属性描述的认证因素:

plugin: 认证插件的名称。
authentication_string: 认证字符串的值。
passwordless: 一个标志,表示用户是否可以在没有密码的情况下使用(仅使用安全令牌作为唯一的认证方法)。
requires_registration: 一个定义用户账户是否已注册安全令牌的标志。
第一个和第二个数组元素描述了多因素认证因素 2 和 3。

如果没有属性适用,则User_attributes为NULL。

例子:一个具有次要密码和部分撤销数据库权限的账户在列值中具有additional_password和Restrictions属性:

mysql> SELECT User_attributes FROM mysql.User WHERE User = \’u\’\\G
*************************** 1\\. row ***************************
User_attributes: {\”Restrictions\”:
[{\”Database\”: \”mysql\”, \”Privileges\”: [\”SELECT\”]}],
\”additional_password\”: \”*hashed_credentials*\”}

要确定存在哪些属性,请使用JSON_KEYS()函数:

SELECT User, Host, JSON_KEYS(User_attributes)
FROM mysql.user WHERE User_attributes IS NOT NULL;

要提取特定属性,例如Restrictions,请执行以下操作:

SELECT User, Host, User_attributes->>\’$.Restrictions\’
FROM mysql.user WHERE User_attributes->>\’$.Restrictions\’ <> \’\’;

这是存储在multi_factor_authentication中的信息示例:

{
\”multi_factor_authentication\”: [
{
\”plugin\”: \”authentication_ldap_simple\”,
\”passwordless\”: 0,
\”authentication_string\”: \”ldap auth string\”,
\”requires_registration\”: 0
},
{
\”plugin\”: \”authentication_fido\”,
\”passwordless\”: 0,
\”authentication_string\”: \”\”,
\”requires_registration\”: 1
}
]
}

tables_priv 和 columns_priv 授权表

在访问控制的第二阶段,服务器执行请求验证,以确保每个客户端对其发出的每个请求都具有足够的权限。除了user和db授权表外,服务器还可能在涉及表的请求中查阅tables_priv和columns_priv表。后者在表和列级别提供更精细的权限控制。它们具有以下表中显示的列。

表 8.6 tables_priv 和 columns_priv 表列

表名tables_privcolumns_priv范围列主机主机数据库数据库用户用户表名表名列名权限列表权限列权限列权限其他列时间戳时间戳授权者
时间戳 和 授权者 列分别设置为当前时间戳和CURRENT_USER值,但其他情况下未使用。

procs_priv 授权表

为了验证涉及存储例程的请求,服务器可能会查阅procs_priv表,该表具有以下表中显示的列。

表 8.7 procs_priv 表列

表名procs_priv范围列主机数据库用户例程名例程类型权限列Proc 权限其他列时间戳授权者
例程类型 列是一个具有值 \’FUNCTION\’ 或 \’PROCEDURE\’ 的ENUM列,用于指示行所指的例程类型。该列使得可以分别为具有相同名称的函数和过程授予权限。

时间戳 和 授权者 列未使用。

proxies_priv 授权表

proxies_priv 表记录有关代理账户的信息。它具有以下列:

主机,用户:代理账户;即具有被代理账户的PROXY权限的账户。
被代理主机,被代理用户:被代理账户。
授权者,时间戳:未使用。
With_grant:代理账户是否可以将PROXY权限授予其他账户。

要使账户能够向其他账户授予PROXY特权,必须在proxies_priv表中具有一行,其中With_grant设置为 1,Proxied_host和Proxied_user设置为指示可以授予特权的账户或账户。例如,在 MySQL 安装期间创建的\’root\’@\’localhost\’账户在proxies_priv表中有一行,该行允许为\’\’@\’\’,即所有用户和所有主机,授予PROXY特权。这使得root能够设置代理用户,以及委派给其他账户权限设置代理用户的权限。参见 Section 8.2.19, “Proxy Users”。

全局授权授权表

global_grants表列出了动态全局特权当前分配给用户账户的情况。该表包含以下列:

用户,主机:被授予权限的账户的用户名和主机名。
权限:权限名称。
WITH_GRANT_OPTION:账户是��可以向其他账户授予特权。

默认角色授权表

default_roles表列出了默认用户角色。它包含以下列:

主机,用户:应用默认角色的账户或角色。
DEFAULT_ROLE_HOST,DEFAULT_ROLE_USER:默认角色。

角色边缘授权表

role_edges表列出了角色子图的边缘。它包含以下列:

FROM_HOST,FROM_USER:被授予角色的账户。
TO_HOST,TO_USER:授予给账户的角色。
WITH_ADMIN_OPTION:账户是否可以通过使用WITH ADMIN OPTION向其他账户授予角色和撤销角色。

密码历史授权表

password_history表包含有关密码更改的信息。它包含以下列:

主机,用户:密码更改发生的账户。
密码时间戳:密码更改发生的时间。
密码:新密码哈希值。

password_history表累积每个账户的足够数量的非空密码,以使 MySQL 能够执行针对账户密码历史长度和重用间隔的检查。当密码更改尝试发生时,会自动修剪超出这两个限制的条目。

注意

空密码不计入密码历史记录,并可随时重新使用。

如果账户被重命名,其条目也将被重命名以匹配。如果账户被删除或其认证插件被更改,其条目将被移除。

授权表范围列属性

授权表中的范围列包含字符串。每个的默认值为空字符串。以下表显示了每个列中允许的字符数。

表 8.8 授权表范围列长度

列名最大允许字符数主机,代理主机255(在 MySQL 8.0.17 之前为 60)用户,代理用户32数据库64表名64Column_name64Routine_name64
Host 和 Proxied_host 的值在存储在授权表中之前会被转换为小写。

为了访问检查目的,User、Proxied_user、authentication_string、Db 和 Table_name 的值的比较是区分大小写的。Host、Proxied_host、Column_name 和 Routine_name 的值的比较是不区分大小写的。

授权表权限列属性

user 和 db 表中列出了每个权限在一个单独的列中声明为 ENUM(\’N\’,\’Y\’) DEFAULT \’N\’。换句话说,每个权限可以被禁用或启用,默认情况下为禁用。

tables_priv、columns_priv 和 procs_priv 表将权限列声明为 SET 列。这些列中的值可以包含由表控制的任何权限的任意组合。只有列值中列出的权限才会被启用。

表 8.9 Set-Type Privilege Column Values

表名列名可能的集合元素tables_privTable_priv\’Select\’, \’Insert\’, \’Update\’, \’Delete\’, \’Create\’, \’Drop\’, \’Grant\’, \’References\’, \’Index\’, \’Alter\’, \’Create View\’, \’Show view\’, \’Trigger\’tables_privColumn_priv\’Select\’, \’Insert\’, \’Update\’, \’References\’columns_privColumn_priv\’Select\’, \’Insert\’, \’Update\’, \’References\’procs_privProc_priv\’Execute\’, \’Alter Routine\’, \’Grant\’
只有 user 和 global_grants 表指定了管理权限,例如 RELOAD、SHUTDOWN 和 SYSTEM_VARIABLES_ADMIN。管理操作是对服务器本身的操作,不是特定于数据库的,因此没有理由在其他授权表中列出这些权限。因此,服务器只需要查看 user 和 global_grants 表来确定用户是否可以执行管理操作。

FILE 权限也仅在 user 表中指定。它不是一种管理权限,而是用户在服务器主机上读取或写入文件的能力与所访问的数据库无关。

授权表并发性

从 MySQL 8.0.22 开始,为了允许在 MySQL 授权表上进行并发的 DML 和 DDL 操作,以前在 MySQL 授权表上获取行锁的读操作将作为非锁定读取执行。在 MySQL 授权表上执行为非锁定读取的操作包括:

通过联接列表和子查询从授权表中读取数据的 SELECT 语句和其他只读语句,包括使用任何事务隔离级别的 SELECT … FOR SHARE 语句。
从授权表中读取数据的 DML 操作(通过连接列表或子查询)但不修改它们,在任何事务隔离级别下使用。

从授权表中读取数据时不再获取行锁的语句,在使用基于语句的复制时执行会报告警告。

当使用 -binlog_format=mixed 时,从授权表中读取数据的 DML 操作会被写入二进制日志作为行事件,以使操作对混合模式复制安全。

SELECT … FOR SHARE 语句从授权表中读取数据时会报告警告。使用FOR SHARE子句时,不支持在授权表上进行读取锁定。

从授权表中读取数据并使用SERIALIZABLE隔离级别执行的 DML 操作会报告警告。在使用SERIALIZABLE隔离级别时通常会获取的读取锁在授权表上不受支持。

8.2.4 指定账户名

原文:dev.mysql.com/doc/refman/8.0/en/account-names.html

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 指定角色名称

原文:dev.mysql.com/doc/refman/8.0/en/role-names.html

MySQL 角色名称指的是权限的命名集合。有关角色使用示例,请参阅第 8.2.10 节“使用角色”。

角色名称的语法和语义与帐户名称类似;请参阅第 8.2.4 节“指定帐户名称”。在授予表中存储时,它们具有与帐户名称相同的属性,这些属性在授予表作用域列属性中描述。

角色名称在以下几个方面与帐户名称不同:

角色名称的用户部分不能留空。因此,没有类似于“匿名用户”概念的“匿名角色”。
对于帐户名称,省略角色名称的主机部分将导致主机部分为\’%\’。但是,与帐户名称中的\’%\’不同,在角色名称中的\’%\’主机部分没有通配符属性。例如,对于作为角色名称使用的名称\’me\’@\’%\’,主机部分(\’%\’)只是一个文字值;它没有“任何主机”匹配属性。
在角色名称的主机部分中使用的网络掩码表示法没有意义。
在几种情况下,帐户名称允许为CURRENT_USER()。角色名称不允许。

mysql.user系统表中的一行可以同时充当帐户和角色。在这种情况下,在将名称用作角色名称的上下文中,任何特殊的用户或主机名匹配属性都不适用。例如,您不能执行以下语句,并期望它设置当前会话角色,使用所有具有用户部分为myrole和任何主机名的角色:

SET ROLE \’myrole\’@\’%\’;

相反,该语句将会话的活动角色设置为名称为\’myrole\’@\’%\’的角色。

因此,通常只使用用户名称部分指定角色名称,并让主机名部分隐式地为\’%\’。如果您打算创建一个既可以作为角色又可以从给定主机连接的用户帐户的名称,则指定具有非\’%\’主机部分的角色可能很有用。

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

原文:dev.mysql.com/doc/refman/8.0/en/connection-access.html

当你尝试连接到 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 阶段:请求验证

原文:dev.mysql.com/doc/refman/8.0/en/request-access.html

服务器接受连接后,进入访问控制的第 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 添加账户、分配权限和删除账户

原文:dev.mysql.com/doc/refman/8.0/en/creating-accounts.html

要管理 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\’;

8.2.9 保留帐户

原文:dev.mysql.com/doc/refman/8.0/en/reserved-accounts.html

MySQL 安装过程的一部分是数据目录初始化(请参阅 Section 2.9.1,“初始化数据目录”)。在数据目录初始化期间,MySQL 创建应被视为保留的用户帐户:

\’root\’@\’localhost: 用于管理目的。此帐户具有所有特权,是系统帐户,并且可以执行任何操作。
严格来说,此帐户名称并非保留,因为某些安装将root帐户重命名为其他名称,以避免暴露具有众所周知名称的高度特权帐户。
\’mysql.sys\’@\’localhost\’: 用作sys模式对象的DEFINER。使用mysql.sys帐户可以避免如果 DBA 重命名或删除root帐户而导致的问题。此帐户已锁定,因此不能用于客户端连接。
\’mysql.session\’@\’localhost\’: 内部使用的帐户,用于插件访问服务器。此帐户已锁定,因此不能用于客户端连接。该帐户是系统帐户。
\’mysql.infoschema\’@\’localhost\’: 用作INFORMATION_SCHEMA视图的DEFINER。使用mysql.infoschema帐户可以避免如果 DBA 重命名或删除 root 帐户而导致的问题。此帐户已锁定,因此不能用于客户端连接。

8.2.10 使用角色

原文:dev.mysql.com/doc/refman/8.0/en/roles.html

MySQL 角色是一组命名的权限集合。与用户帐户一样,角色可以被授予和撤销权限。

用户帐户可以被授予角色,从而向帐户授予与每个角色相关联的权限。这使得可以将一组权限分配给帐户,并为所需的权限分配提供了一个方便的替代方法,用于概念化所需的权限分配并实施它们。

以下列表总结了 MySQL 提供的角色管理功能:

CREATE ROLE 和 DROP ROLE 创建和移除角色。
GRANT 和 REVOKE 分配权限以撤销用户帐户和角色的权限。
SHOW GRANTS 显示用户帐户和角色的权限和角色分配。
SET DEFAULT ROLE 指定默认情况下活动的帐户角色。
SET ROLE 更改当前会话中的活动角色。
CURRENT_ROLE() 函数显示当前会话中活动的角色。
mandatory_roles 和 activate_all_roles_on_login 系统变量允许定义强制角色和用户登录到服务器时自动激活授予的角色。

有关单个角色操作语句的描述(包括使用它们所需的权限),请参阅第 15.7.1 节,“帐户管理语句”。以下讨论提供了角色使用的示例。除非另有说明,此处显示的 SQL 语句应使用具有足够管理权限的 MySQL 帐户(如 root 帐户)执行。

创建角色并授予权限
定义强制角色
检查角色权限
激活角色
撤销角色或角色权限
删除角色
用户和角色的可互换性

创建角色并授予权限

考虑以下情景:

一个应用程序使用名为app_db的数据库。
与应用程序关联,可以为创建和维护应用程序的开发人员以及与之交互的用户创建帐户。
开发人员需要对数据库拥有完全访问权限。一些用户只需要读取访问权限,其他用户需要读取/写入访问权限。

为了避免向可能有许多用户帐户单独授予权限,将角色创建为所需权限集的名称。这样可以轻松地向用户帐户授予所需的权限,方法是授予适当的角色。

要创建角色,请使用CREATE ROLE语句:

CREATE ROLE \’app_developer\’, \’app_read\’, \’app_write\’;

角色名称与用户帐户名称非常相似,由\’*user_name*\’@\’*host_name*\’格式中的用户部分和主机部分组成。如果省略主机部分,则默认为\’%\’。用户和主机部分可以不带引号,除非它们包含特殊字符,如-或%。与帐户名称不同,角色名称的用户部分不能为空。有关更多信息,请参见第 8.2.5 节“指定角色名称”。

要为角色分配权限,执行与为用户帐户分配权限相同的语法的GRANT语句:

GRANT ALL ON app_db.* TO \’app_developer\’;
GRANT SELECT ON app_db.* TO \’app_read\’;
GRANT INSERT, UPDATE, DELETE ON app_db.* TO \’app_write\’;

现在假设最初您需要一个开发人员帐户,两个需要只读访问权限的用户帐户和一个需要读取/写入访问权限的用户帐户。使用CREATE USER创建这些帐户:

CREATE USER \’dev1\’@\’localhost\’ IDENTIFIED BY \’dev1pass\’;
CREATE USER \’read_user1\’@\’localhost\’ IDENTIFIED BY \’read_user1pass\’;
CREATE USER \’read_user2\’@\’localhost\’ IDENTIFIED BY \’read_user2pass\’;
CREATE USER \’rw_user1\’@\’localhost\’ IDENTIFIED BY \’rw_user1pass\’;

为每个用户帐户分配所需的权限,您可以使用与刚刚显示的相同形式的GRANT语句,但这需要为每个用户枚举单独的权限。相反,使用另一种允许授予角色而不是权限的GRANT语法:

GRANT \’app_developer\’ TO \’dev1\’@\’localhost\’;
GRANT \’app_read\’ TO \’read_user1\’@\’localhost\’, \’read_user2\’@\’localhost\’;
GRANT \’app_read\’, \’app_write\’ TO \’rw_user1\’@\’localhost\’;

对于rw_user1帐户的GRANT语句授予读取和写入角色,这些角色结合起来提供所需的读取和写入权限。

将角色授予帐户的GRANT语法与授予权限的语法不同:有一个ON子句用于分配权限,而没有ON子句用于分配角色。因为语法不同,您不能在同一语句中混合分配权限和角色。(允许向帐户分配权限和角色,但必须使用适用于要授予的内容的语法的单独的GRANT语句。)截至 MySQL 8.0.16,无法向匿名用户授予角色。

创建角色时,角色被锁定,没有密码,并分配默认的身份验证插件。(这些角色属性可以稍后由具有全局CREATE USER权限的用户使用ALTER USER语句更改。)

当角色被锁定时,无法用于服务器身份验证。如果解锁,则可以用于身份验证。这是因为角色和用户都是授权标识符,有很多共同之处,很少有区别。另请参阅用户和角色的可互换性。

定义强制角色

可以通过在mandatory_roles系统变量的值中命名角色来指定角色为强制角色。服务器将强制角色视为授予所有用户的角色,因此不需要显式授予任何帐户。

要在服务器启动时指定强制角色,请在服务器的my.cnf文件中定义mandatory_roles:

[mysqld]
mandatory_roles=\’role1,role2@localhost,r3@%.example.com\’

要在运行时设置和持久化mandatory_roles,请使用以下语句:

SET PERSIST mandatory_roles = \’role1,role2@localhost,r3@%.example.com\’;

SET PERSIST为运行中的 MySQL 实例设置一个值。它还保存该值,导致其在后续服务器重启时保留。要更改运行中的 MySQL 实例的值,而不使其在后续重启时保留,使用GLOBAL关键字而不是PERSIST。请参阅第 15.7.6.1 节,“变量赋值的 SET 语法”。

设置mandatory_roles需要ROLE_ADMIN权限,除了通常需要设置全局系统变量的SYSTEM_VARIABLES_ADMIN权限(或已弃用的SUPER权限)。

强制角色,就像显式授予的角色一样,在激活之前不会生效(请参阅激活角色)。在登录时,如果启用了activate_all_roles_on_login系统变量,则为所有授予的角色激活,否则为设置为默认角色的角色激活。在运行时,SET ROLE激活角色。

在mandatory_roles值中命名的角色不能通过REVOKE或DROP ROLE或DROP USER来撤销。

为防止会话默认成为系统会话,具有SYSTEM_USER权限的角色不能列在mandatory_roles系统变量的值中:

如果在启动时将mandatory_roles分配给具有SYSTEM_USER权限的角色,则服务器会向错误日志写入消息并退出。
如果在运行时将mandatory_roles分配给具有SYSTEM_USER权限的角色,则会发生错误,并且mandatory_roles值保持不变。

即使有此保障,最好避免通过角色授予SYSTEM_USER权限,以防止权限升级的可能性。

如果在mysql.user系统表中不存在mandatory_roles中命名的角色,则不会将该角色授予用户。当服务器尝试为用户激活角色时,它不会将不存在的角色视为强制角色,并将警告写入错误日志。如果稍后创建了角色并因此变为有效,则可能需要使用FLUSH PRIVILEGES使服务器将其视为强制角色。

SHOW GRANTS 根据第 15.7.7.21 节,“SHOW GRANTS Statement”中描述的规则显示强制角色。

检查角色权限

要验证分配给账户的权限,请使用SHOW GRANTS。例如:

mysql> SHOW GRANTS FOR \’dev1\’@\’localhost\’;
+————————————————-+
| Grants for dev1@localhost |
+————————————————-+
| GRANT USAGE ON *.* TO `dev1`@`localhost` |
| GRANT `app_developer`@`%` TO `dev1`@`localhost` |
+————————————————-+

然而,这显示了每个授予的角色,而没有将其“展开”为角色代表的权限。要显示角色权限,还需添加一个USING子句,命名要显示权限的授予角色:

mysql> SHOW GRANTS FOR \’dev1\’@\’localhost\’ USING \’app_developer\’;
+———————————————————-+
| Grants for dev1@localhost |
+———————————————————-+
| GRANT USAGE ON *.* TO `dev1`@`localhost` |
| GRANT ALL PRIVILEGES ON `app_db`.* TO `dev1`@`localhost` |
| GRANT `app_developer`@`%` TO `dev1`@`localhost` |
+———————————————————-+

类似地验证每种类型的用户:

mysql> SHOW GRANTS FOR \’read_user1\’@\’localhost\’ USING \’app_read\’;
+——————————————————–+
| Grants for read_user1@localhost |
+——————————————————–+
| GRANT USAGE ON *.* TO `read_user1`@`localhost` |
| GRANT SELECT ON `app_db`.* TO `read_user1`@`localhost` |
| GRANT `app_read`@`%` TO `read_user1`@`localhost` |
+——————————————————–+
mysql> SHOW GRANTS FOR \’rw_user1\’@\’localhost\’ USING \’app_read\’, \’app_write\’;
+——————————————————————————+
| Grants for rw_user1@localhost |
+——————————————————————————+
| GRANT USAGE ON *.* TO `rw_user1`@`localhost` |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `app_db`.* TO `rw_user1`@`localhost` |
| GRANT `app_read`@`%`,`app_write`@`%` TO `rw_user1`@`localhost` |
+——————————————————————————+

SHOW GRANTS 根据第 15.7.7.21 节,“SHOW GRANTS Statement”中描述的规则显示强制角色。

激活角色

授予用户账户的角色可以在账户会话中处于活动或非活动状态。如果授予的角色在会话中处于活动状态,则其权限生效;否则,不生效。要确定当前会话中哪些角色处于活动状态,请使用CURRENT_ROLE()函数。

默认情况下,将角色授予给一个账户或在mandatory_roles系统变量值中命名它不会自动导致角色在账户会话中变为活动状态。例如,因为在前面的讨论中到目前为止没有激活任何rw_user1角色,如果您以rw_user1身份连接到服务器并调用CURRENT_ROLE()函数,结果是NONE(没有活动角色):

mysql> SELECT CURRENT_ROLE();
+—————-+
| CURRENT_ROLE() |
+—————-+
| NONE |
+—————-+

要指定每次用户连接到服务器并进行身份验证时应激活哪些角色,请使用SET DEFAULT ROLE。要将默认设置为早期创建的每个账户的所有分配角色,请使用此语句:

SET DEFAULT ROLE ALL TO
\’dev1\’@\’localhost\’,
\’read_user1\’@\’localhost\’,
\’read_user2\’@\’localhost\’,
\’rw_user1\’@\’localhost\’;

现在,如果您以rw_user1身份连接,CURRENT_ROLE()的初始值反映了新的默认角色分配:

mysql> SELECT CURRENT_ROLE();
+——————————–+
| CURRENT_ROLE() |
+——————————–+
| `app_read`@`%`,`app_write`@`%` |
+——————————–+

要在用户连接到服务器时自动激活所有明确授予和强制性角色,请启用activate_all_roles_on_login系统变量。默认情况下,自动角色激活被禁用。

在一个会话中,用户可以执行SET ROLE来改变活动角色集。例如,对于rw_user1:

mysql> SET ROLE NONE; SELECT CURRENT_ROLE();
+—————-+
| CURRENT_ROLE() |
+—————-+
| NONE |
+—————-+
mysql> SET ROLE ALL EXCEPT \’app_write\’; SELECT CURRENT_ROLE();
+—————-+
| CURRENT_ROLE() |
+—————-+
| `app_read`@`%` |
+—————-+
mysql> SET ROLE DEFAULT; SELECT CURRENT_ROLE();
+——————————–+
| CURRENT_ROLE() |
+——————————–+
| `app_read`@`%`,`app_write`@`%` |
+——————————–+

第一个SET ROLE语句取消所有角色。第二个使rw_user1有效地只读。第三个恢复默认角色。

存储程序和视图对象的有效用户受DEFINER和SQL SECURITY属性的影响,这些属性确定执行是在调用者还是定义者上下文中发生(参见第 27.6 节,“存储对象访问控制”):

在调用者上下文中执行的存储程序和视图对象将使用当前会话中处于活动状态的角色执行。
在定义者上下文中执行的存储程序和视图对象将使用其DEFINER属性中命名的用户的默认角色执行。如果启用了activate_all_roles_on_login,这样的对象将使用授予DEFINER用户的所有角色,包括强制性角色。对于存储程序,如果执行应该使用与默认不同的角色,则程序体可以执行SET ROLE来激活所需的角色。这必须谨慎进行,因为分配给角色的权限可以更改。

撤销角色或角色权限

就像角色可以授予给一个账户一样,它们也可以从一个账户中撤销:

REVOKE *role* FROM *user*;

在mandatory_roles系统变量值中命名的角色不能被撤销。

REVOKE也可以应用于角色以修改授予其的权限。这不仅影响角色本身,还影响分配了该角色的任何帐户。假设您想暂时使所有应用程序用户只读。为此,请使用REVOKE来从app_write角色中撤销修改权限:

REVOKE INSERT, UPDATE, DELETE ON app_db.* FROM \’app_write\’;

正如所发生的那样,这将使角色完全没有任何权限,可以使用SHOW GRANTS来查看(这表明此语句可以与角色一起使用,而不仅仅是用户):

mysql> SHOW GRANTS FOR \’app_write\’;
+—————————————+
| Grants for app_write@% |
+—————————————+
| GRANT USAGE ON *.* TO `app_write`@`%` |
+—————————————+

因为从角色中撤销权限会影响分配了修改后角色的任何用户的权限,rw_user1现在没有表修改权限(INSERT、UPDATE和DELETE不再存在):

mysql> SHOW GRANTS FOR \’rw_user1\’@\’localhost\’
USING \’app_read\’, \’app_write\’;
+—————————————————————-+
| Grants for rw_user1@localhost |
+—————————————————————-+
| GRANT USAGE ON *.* TO `rw_user1`@`localhost` |
| GRANT SELECT ON `app_db`.* TO `rw_user1`@`localhost` |
| GRANT `app_read`@`%`,`app_write`@`%` TO `rw_user1`@`localhost` |
+—————————————————————-+

实际上,rw_user1读/写用户已成为只读用户。对于被授予app_write角色的任何其他帐户也是如此,说明使用角色使得不必为单个帐户修改权限。

要恢复角色的修改权限,只需重新授予它们:

GRANT INSERT, UPDATE, DELETE ON app_db.* TO \’app_write\’;

现在rw_user1再次具有修改权限,任何其他被授予app_write角色的帐户也是如此。

删除角色

要删除角色,请使用DROP ROLE:

DROP ROLE \’app_read\’, \’app_write\’;

删除一个角色会从授予它的每个帐户中撤销该角色。

在mandatory_roles系统变量值中命名的角色不能被删除。

用户和角色的互换性

正如早些时候暗示的那样,对于SHOW GRANTS,它显示用户帐户或角色的授权,帐户和角色可以互换使用。

角色和用户之间的一个区别是,CREATE ROLE默认创建一个被锁定的授权标识符,而CREATE USER默认创建一个未锁定的授权标识符。您应该记住这个区别不是不可改变的;具有适当权限的用户可以在创建后锁定或解锁角色或(其他)用户。

如果数据库管理员有一个偏好,即特定的授权标识符必须是一个角色,那么可以使用命名方案来传达这一意图。例如,您可以为所有您打算作为角色而不是其他内容的授权标识符使用r_前缀。

角色和用户之间的另一个区别在于用于管理它们的权限的可用性:

CREATE ROLE 和 DROP ROLE 权限仅允许使用 CREATE ROLE 和 DROP ROLE 语句。
CREATE USER 权限允许使用 ALTER USER、CREATE ROLE、CREATE USER、DROP ROLE、DROP USER、RENAME USER 和 REVOKE ALL PRIVILEGES 语句。

因此,CREATE ROLE 和 DROP ROLE 权限不如 CREATE USER 强大,可能授予那些只允许创建和删除角色而不执行更一般帐户操作的用户。

关于权限和用户与角色的可互换性,您可以将用户帐户视为角色并将该帐户授予另一个用户或角色。效果是将该帐户的权限和角色授予另一个用户或角色。

这组语句表明您可以将用户授予用户,将角色授予用户,将用户授予角色,或将角色授予角色:

CREATE USER \’u1\’;
CREATE ROLE \’r1\’;
GRANT SELECT ON db1.* TO \’u1\’;
GRANT SELECT ON db2.* TO \’r1\’;
CREATE USER \’u2\’;
CREATE ROLE \’r2\’;
GRANT \’u1\’, \’r1\’ TO \’u2\’;
GRANT \’u1\’, \’r1\’ TO \’r2\’;

每种情况的结果是将授予对象的权限与授予对象相关联的权限授予给受让对象。执行这些语句后,u2 和 r2 分别从用户 (u1) 和角色 (r1) 获得了权限:

mysql> SHOW GRANTS FOR \’u2\’ USING \’u1\’, \’r1\’;
+————————————-+
| Grants for u2@% |
+————————————-+
| GRANT USAGE ON *.* TO `u2`@`%` |
| GRANT SELECT ON `db1`.* TO `u2`@`%` |
| GRANT SELECT ON `db2`.* TO `u2`@`%` |
| GRANT `u1`@`%`,`r1`@`%` TO `u2`@`%` |
+————————————-+
mysql> SHOW GRANTS FOR \’r2\’ USING \’u1\’, \’r1\’;
+————————————-+
| Grants for r2@% |
+————————————-+
| GRANT USAGE ON *.* TO `r2`@`%` |
| GRANT SELECT ON `db1`.* TO `r2`@`%` |
| GRANT SELECT ON `db2`.* TO `r2`@`%` |
| GRANT `u1`@`%`,`r1`@`%` TO `r2`@`%` |
+————————————-+

前面的例子仅供参考,但用户帐户和角色的可互换性具有实际应用,例如在以下情况下:假设一个传统的应用开发项目在 MySQL 的角色出现之前就开始了,因此与该项目相关的所有用户帐户都直接被授予权限(而不是通过授予角色而获得权限)。其中一个帐户是最初被授予权限的开发人员帐户如下:

CREATE USER \’old_app_dev\’@\’localhost\’ IDENTIFIED BY \’old_app_devpass\’;
GRANT ALL ON old_app.* TO \’old_app_dev\’@\’localhost\’;

如果该开发人员离开项目,则有必要将权限分配给另一个用户,或者如果开发活动已扩展,则可能需要分配给多个用户。以下是处理此问题的一些方法:

不使用角色:更改帐户密码,以防止原始开发人员使用它,并让新开发人员使用该帐户:
ALTER USER \’old_app_dev\’@\’localhost\’ IDENTIFIED BY \’*new_password*\’;
使用角色:锁定帐户以防止任何人使用它连接到服务器:
ALTER USER \’old_app_dev\’@\’localhost\’ ACCOUNT LOCK;
然后将该帐户视为一个角色。对于项目中的每个新开发人员,创建一个新帐户并授予其原始开发人员帐户:
CREATE USER \’new_app_dev1\’@\’localhost\’ IDENTIFIED BY \’*new_password*\’;
GRANT \’old_app_dev\’@\’localhost\’ TO \’new_app_dev1\’@\’localhost\’;
该效果是将原始开发者账户的权限分配给新账户。

#以上关于MySQL8 中文参考(二十四)的相关内容来源网络仅供参考,相关信息请以官方公告为准!

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92415.html

Like (0)
CSDN的头像CSDN
Previous 2024年6月27日
Next 2024年6月27日

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注