文档主页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


8.2.3 授权表

mysql 系统数据库包含多个授权表,这些表包含有关用户帐户及其拥有的权限的信息。本节介绍这些表。有关系统数据库中其他表的信息,请参阅 第 7.3 节,“mysql 系统模式”

此处的讨论描述了授权表的底层结构,以及服务器在与客户端交互时如何使用其内容。但是,通常您不会直接修改授权表。当您使用帐户管理语句(如 CREATE USERGRANTREVOKE)来设置帐户和控制每个帐户可用的权限时,会间接进行修改。请参阅 第 15.7.1 节,“帐户管理语句”。当您使用此类语句执行帐户操作时,服务器会代表您修改授权表。

注意

不建议使用 INSERTUPDATEDELETE 等语句直接修改授权表,这样做风险自负。服务器可以自由忽略由于此类修改而变得格式错误的行。

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

授权表概述

以下 mysql 数据库表包含授权信息:

有关静态和动态全局权限之间差异的信息,请参阅 静态与动态权限

在 MySQL 8.4 中,授权表使用 InnoDB 存储引擎,并且是事务性的。在 MySQL 8.4 之前,授权表使用 MyISAM 存储引擎,并且是非事务性的。授权表存储引擎的这种变化使得账户管理语句(例如 CREATE USERGRANT)的行为也随之改变。以前,命名多个用户的账户管理语句可能对某些用户成功,而对其他用户失败。现在,每个语句都是事务性的,要么对所有命名的用户都成功,要么在发生任何错误时回滚并且没有任何影响。

每个授权表都包含作用域列和权限列。

  • 作用域列确定表中每一行的作用域;也就是说,该行适用的上下文。例如,user 表中 HostUser 值分别为 'h1.example.net''bob' 的行适用于从主机 h1.example.net 通过指定用户名 bob 的客户端进行的身份验证连接。类似地,db 表中 HostUserDb 列值分别为 'h1.example.net''bob''reports' 的行适用于 bob 从主机 h1.example.net 连接以访问 reports 数据库的情况。tables_privcolumns_priv 表包含作用域列,指示每一行适用的表或表/列组合。procs_priv 作用域列指示每一行适用的存储例程。

  • 权限列指示表行授予哪些权限;也就是说,它允许执行哪些操作。服务器组合各种授权表中的信息,以形成用户权限的完整描述。第 8.2.7 节“访问控制,阶段 2:请求验证”描述了相关规则。

此外,授权表可能包含用于除作用域或权限评估以外的其他目的的列。

服务器按以下方式使用授权表:

  • user 表作用域列确定是拒绝还是允许传入连接。对于允许的连接,user 表中授予的任何权限都表示用户的静态全局权限。此表中授予的任何权限都适用于服务器上的所有数据库。

    注意

    由于任何静态全局权限都被视为所有数据库的权限,因此任何静态全局权限都使用户能够使用 SHOW DATABASES 或通过检查 INFORMATION_SCHEMASCHEMATA 表来查看所有数据库名称,但已通过部分撤销在数据库级别受到限制的数据库除外。

  • global_grants 表列出了当前分配给用户帐户的动态全局权限。对于每一行,作用域列确定哪个用户拥有权限列中命名的权限。

  • db 表作用域列确定哪些用户可以从哪些主机访问哪些数据库。权限列确定允许的操作。在数据库级别授予的权限适用于该数据库和该数据库中的所有对象,例如表和存储程序。

  • tables_privcolumns_priv 表类似于 db 表,但粒度更细:它们应用于表和列级别,而不是数据库级别。在表级别授予的权限适用于该表及其所有列。在列级别授予的权限仅适用于特定列。

  • procs_priv 表适用于存储例程(存储过程和函数)。在例程级别授予的权限仅适用于单个过程或函数。

  • proxies_priv 表指示哪些用户可以充当其他用户的代理,以及用户是否可以将 PROXY 权限授予其他用户。

  • default_rolesrole_edges 表包含有关角色关系的信息。

  • password_history 表保留以前选择的密码,以便对密码重用进行限制。请参见 第 8.2.15 节“密码管理”

服务器在启动时将授权表的内容读入内存。您可以通过发出 FLUSH PRIVILEGES 语句或执行 mysqladmin flush-privilegesmysqladmin reload 命令来指示它重新加载这些表。对授权表的更改将按 第 8.2.13 节“权限更改何时生效” 中的说明生效。

修改帐户时,最好验证您的更改是否达到了预期效果。要检查给定帐户的权限,请使用 SHOW GRANTS 语句。例如,要确定授予用户名和主机名值分别为 bobpc84.example.com 的帐户的权限,请使用以下语句:

SHOW GRANTS FOR 'bob'@'pc84.example.com';

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

SHOW CREATE USER 'bob'@'pc84.example.com';

user 和 db 授权表

服务器在访问控制的第一阶段和第二阶段都使用 mysql 数据库中的 userdb 表(请参见 第 8.2 节“访问控制和帐户管理”)。userdb 表中的列如下所示。

表 8.4 user 和 db 表列

表名 user db
作用域列 Host Host
User Db
User
权限列 Select_priv Select_priv
Insert_priv Insert_priv
Update_priv Update_priv
Delete_priv Delete_priv
Index_priv Index_priv
Alter_priv Alter_priv
Create_priv Create_priv
Drop_priv Drop_priv
Grant_priv Grant_priv
Create_view_priv Create_view_priv
Show_view_priv Show_view_priv
Create_routine_priv Create_routine_priv
Alter_routine_priv Alter_routine_priv
Execute_priv Execute_priv
Trigger_priv Trigger_priv
Event_priv Event_priv
Create_tmp_table_priv Create_tmp_table_priv
Lock_tables_priv Lock_tables_priv
References_priv References_priv
Reload_priv
Shutdown_priv
Process_priv
File_priv
Show_db_priv
Super_priv
Repl_slave_priv
Repl_client_priv
Create_user_priv
Create_tablespace_priv
Create_role_priv
Drop_role_priv
安全列 ssl_type
ssl_cipher
x509_issuer
x509_subject
plugin
authentication_string
password_expired
password_last_changed
password_lifetime
account_locked
Password_reuse_history
Password_reuse_time
Password_require_current
User_attributes
资源控制列 max_questions
max_updates
max_connections
max_user_connections

user 表的 pluginauthentication_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_passwordcaching_sha2_password)的帐户才为非 NULL。对于其他帐户(例如使用外部身份验证系统进行身份验证的帐户),该值为 NULL

password_last_changedCREATE USERALTER USERSET 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 对应于帐户的 PASSWORD REQUIRE 选项的值,如下表所示。

表 8.5 允许的 Password_require_current 值

Password_require_current 值 对应的 PASSWORD REQUIRE 选项
'Y' PASSWORD REQUIRE CURRENT
'N' PASSWORD REQUIRE CURRENT OPTIONAL
NULL PASSWORD REQUIRE CURRENT DEFAULT

User_attributes 是一个 JSON 格式的列,用于存储未存储在其他列中的帐户属性。INFORMATION_SCHEMA 通过 USER_ATTRIBUTES 表公开这些属性。

User_attributes 列可以包含以下属性:

  • additional_password:辅助密码(如果有)。请参阅 双密码支持

  • Restrictions:限制列表(如果有)。限制是通过部分撤销操作添加的。属性值是一个元素数组,每个元素都有 DatabaseRestrictions 键,分别表示受限数据库的名称和对其应用的限制(请参阅 第 8.2.12 节,“使用部分撤销进行权限限制”)。

  • Password_locking:失败登录跟踪和临时帐户锁定的条件(如果有)(请参阅 失败登录跟踪和临时帐户锁定)。Password_locking 属性根据 CREATE USERALTER USER 语句的 FAILED_LOGIN_ATTEMPTSPASSWORD_LOCK_TIME 选项进行更新。属性值是一个哈希值,其中包含 failed_login_attemptspassword_lock_time_days 键,指示已为帐户指定的此类选项的值。如果缺少某个键,则其值隐式为 0。如果键值隐式或显式为 0,则禁用相应的功能。

  • multi_factor_authenticationmysql.user 系统表中的行有一个 plugin 列,用于指示身份验证插件。对于单因素身份验证,该插件是唯一的身份验证因素。对于双因素或三因素形式的多因素身份验证,该插件对应于第一个身份验证因素,但必须存储第二个和第三个因素的其他信息。multi_factor_authentication 属性保存此信息。

    multi_factor_authentication 值是一个数组,其中每个数组元素都是一个哈希值,使用以下属性描述一个身份验证因素:

    • plugin:身份验证插件的名称。

    • authentication_string:身份验证字符串值。

    • passwordless:一个标志,表示用户是否打算在没有密码的情况下使用(使用安全令牌作为唯一的身份验证方法)。

    • requires_registration:一个标志,定义用户帐户是否已注册安全令牌。

    第一个和第二个数组元素描述了多因素身份验证因素 2 和 3。

如果没有适用的属性,则 User_attributesNULL

示例:具有辅助密码和部分撤销的数据库权限的帐户在其列值中具有 additional_passwordRestrictions 属性:

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_webauthn",
      "passwordless": 0,
      "authentication_string": "",
      "requires_registration": 1
    }
  ]
}

tables_priv 和 columns_priv 授权表

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

表 8.6 tables_priv 和 columns_priv 表列

表名 tables_priv columns_priv
作用域列 Host Host
Db Db
User User
Table_name Table_name
Column_name
权限列 Table_priv Column_priv
Column_priv
其他列 Timestamp Timestamp
Grantor

TimestampGrantor 列分别设置为当前时间戳和 CURRENT_USER 值,但在其他情况下未使用。

procs_priv 授权表

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

表 8.7 procs_priv 表列

表名 procs_priv
作用域列 Host
Db
User
Routine_name
Routine_type
权限列 Proc_priv
其他列 Timestamp
Grantor

Routine_type 列是一个 ENUM 列,其值为 'FUNCTION''PROCEDURE',用于指示该行引用的例程类型。此列允许分别为具有相同名称的函数和过程授予权限。

TimestampGrantor 列未使用。

proxies_priv 授权表

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

  • HostUser:代理帐户;也就是说,对被代理帐户具有 PROXY 权限的帐户。

  • Proxied_hostProxied_user:被代理帐户。

  • GrantorTimestamp:未使用。

  • With_grant:代理帐户是否可以将 PROXY 权限授予其他帐户。

要使帐户能够将 PROXY 权限授予其他帐户,它在 proxies_priv 表中必须具有一行,其中 With_grant 设置为 1,Proxied_hostProxied_user 设置为指示可以为其授予权限的帐户。例如,在 MySQL 安装期间创建的 'root'@'localhost' 帐户在 proxies_priv 表中具有一行,该行允许为 ''@'' 授予 PROXY 权限,即为所有用户和所有主机授予权限。这使 root 能够设置代理用户,以及将设置代理用户的权限委派给其他帐户。请参阅 第 8.2.19 节,“代理用户”

global_grants 授权表

global_grants 表列出了当前将动态全局权限分配给用户帐户的情况。该表具有以下列:

  • USERHOST:被授予权限的帐户的用户名和主机名。

  • PRIV:权限名称。

  • WITH_GRANT_OPTION:该帐户是否可以将权限授予其他帐户。

default_roles 授权表

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

  • HOSTUSER:应用默认角色的帐户或角色。

  • DEFAULT_ROLE_HOSTDEFAULT_ROLE_USER:默认角色。

role_edges 授权表

role_edges 表列出了角色子图的边。它具有以下列:

  • FROM_HOSTFROM_USER:被授予角色的帐户。

  • TO_HOSTTO_USER:授予该帐户的角色。

  • WITH_ADMIN_OPTION:该帐户是否可以使用 WITH ADMIN OPTION 将角色授予其他帐户并从其他帐户撤销该角色。

password_history 授权表

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

  • HostUser:发生密码更改的帐户。

  • Password_timestamp:密码更改发生的时间。

  • Password:新的密码哈希值。

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

注意

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

如果帐户被重命名,则其条目也会被重命名以匹配。如果删除了帐户或更改了其身份验证插件,则会删除其条目。

授权表范围列属性

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

表 8.8 授权表范围列长度

列名 允许的最大字符数
HostProxied_host 255
UserProxied_user 32
Db 64
Table_name 64
Column_name 64
Routine_name 64

HostProxied_host 值在存储到授权表之前会转换为小写。

出于访问检查目的,UserProxied_userauthentication_stringDbTable_name 值的比较区分大小写。HostProxied_hostColumn_nameRoutine_name 值的比较不区分大小写。

授权表权限列属性

userdb 表在单独的列中列出每个权限,这些列声明为 ENUM('N','Y') DEFAULT 'N'。换句话说,每个权限都可以被禁用或启用,默认情况下是禁用的。

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

表 8.9 Set 类型权限列值

表名 列名 可能的集合元素
tables_priv Table_priv 'Select'、'Insert'、'Update'、'Delete'、'Create'、'Drop'、'Grant'、'References'、'Index'、'Alter'、'Create View'、'Show view'、'Trigger'
tables_priv Column_priv 'Select'、'Insert'、'Update'、'References'
columns_priv Column_priv 'Select'、'Insert'、'Update'、'References'
procs_priv Proc_priv 'Execute'、'Alter Routine'、'Grant'

只有 userglobal_grants 表指定了管理权限,例如 RELOADSHUTDOWNSYSTEM_VARIABLES_ADMIN。管理操作是对服务器本身的操作,而不是特定于数据库的操作,因此没有理由在其他授权表中列出这些权限。因此,服务器只需要查阅 userglobal_grants 表即可确定用户是否可以执行管理操作。

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

授权表并发性

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

  • 使用任何事务隔离级别的 SELECT 语句和其他只读语句,它们通过联接列表和子查询(包括 SELECT ... FOR SHARE 语句)从授权表读取数据。

  • 使用任何事务隔离级别的 DML 操作,它们从授权表(通过联接列表或子查询)读取数据,但不修改它们。

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

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

从授权表读取数据的 SELECT ... FOR SHARE 语句会报告警告。对于 FOR SHARE 子句,授权表不支持读取锁。

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