### 17.3.3 复制权限检查

[17.3.3.1 复制特权的特权\_检查\_用户帐号](replication-privilege-checks-account.html)
[17.3.3.2 组复制通道的权限检查](replication-privilege-checks-gr.html)
[17.3.3.3 从失败的复制权限检查中恢复](replication-privilege-checks-recover.html)

默认情况下，当已被另一台服务器接受的事务应用于副本或组成员时，MySQL 复制（包括组复制）不会执行权限检查。从 MySQL 8.0.18 开始，您可以创建一个具有适当权限的用户帐户来应用通常在通道上复制的事务，并将其指定为`PRIVILEGE_CHECKS_USER`复制应用程序的帐户，使用[`将复制源更改为`](change-replication-source-to.html)语句（来自 MySQL 8.0.23）或[`将主更改为`](change-master-to.html)语句（在 MySQL 8.0.23 之前）。MySQL 然后根据用户帐户的权限检查每个事务，以验证您是否已授权该通道的操作。管理员也可以安全地使用该帐户来申请或重新申请交易[**mysqlbinlog**](mysqlbinlog.html)输出，例如从通道上的复制错误中恢复。

使用一个`PRIVILEGE_CHECKS_USER`帐户有助于保护复制通道，防止未经授权或意外使用特权或不需要的操作。这`PRIVILEGE_CHECKS_USER`在以下情况下，帐户提供了额外的安全层：

-   您正在组织网络上的服务器实例和另一个网络上的服务器实例之间进行复制，例如由云服务提供商提供的实例。

-   您希望将多个内部部署或场外部署作为单独的单元进行管理，而无需授予一个管理员帐户对所有部署的权限。

-   您希望拥有一个管理员帐户，使管理员能够仅执行与复制通道及其复制的数据库直接相关的操作，而不是在服务器实例上拥有广泛的权限。

    您可以通过将这些选项中的一个或两个添加到[`将复制源更改为`](change-replication-source-to.html)\|[`将主更改为`](change-master-to.html)当您指定`PRIVILEGE_CHECKS_USER`占频道：

-   这`REQUIRE_ROW_FORMAT`选项（可从 MySQL 8.0.19 获得）使复制通道仅接受基于行的复制事件。什么时候`REQUIRE_ROW_FORMAT`已设置，您必须使用基于行的二进制日志记录（[`binlog_format=行`](replication-options-binary-log.html#sysvar_binlog_format)) 在源服务器上。在 MySQL 8.0.18 中，`REQUIRE_ROW_FORMAT`不可用，但仍然强烈建议对安全复制通道使用基于行的二进制日志记录。使用基于语句的二进制日志，可能需要一些管理员级别的权限`PRIVILEGE_CHECKS_USER`帐户以成功执行交易。

-   这`REQUIRE_TABLE_PRIMARY_KEY_CHECK`选项（可从 MySQL 8.0.20 获得）使复制通道使用自己的策略进行主键检查。环境`在`表示始终需要主键，并且设置`离开`意味着永远不需要主键。默认设置，`溪流`, 设置会话值[`sql_require_primary_key`](server-system-variables.html#sysvar_sql_require_primary_key)使用从源为每个事务复制的值的系统变量。什么时候`PRIVILEGE_CHECKS_USER`设置，设置`REQUIRE_TABLE_PRIMARY_KEY_CHECK`要么`在`要么`离开`意味着用户帐户不需要会话管理级别权限来设置受限会话变量，这些变量是更改值所必需的[`sql_require_primary_key`](server-system-variables.html#sysvar_sql_require_primary_key).它还标准化了不同来源的复制通道间的行为。

    您授予[`REPLICATION_APPLIER`](privileges-provided.html#priv_replication-applier)使用户帐户显示为`PRIVILEGE_CHECKS_USER`用于复制应用程序线程，并执行内部使用[`二进制日志`](binlog.html)mysqlbinlog 使用的语句。的用户名和主机名`PRIVILEGE_CHECKS_USER`帐户必须遵循中描述的语法[第 6.2.4 节，“指定帐户名称”](account-names.html)，并且用户不能是匿名用户（用户名为空）或`当前用户`.要创建一个新帐户，请使用[`创建用户`](create-user.html).要授予此帐户[`REPLICATION_APPLIER`](privileges-provided.html#priv_replication-applier)特权，使用[`授予`](grant.html)陈述。例如，创建一个用户帐户`priv_repl`，管理员可以从任何主机手动使用`例子.com`域，并且需要加密连接，发出以下语句：


```
mysql> SET sql_log_bin = 0;
mysql> CREATE USER 'priv_repl'@'%.example.com' IDENTIFIED BY 'password' REQUIRE SSL;
mysql> GRANT REPLICATION_APPLIER ON *.* TO 'priv_repl'@'%.example.com';
mysql> SET sql_log_bin = 1;
```

这`设置 sql_log_bin`使用语句，以便帐户管理语句不会添加到二进制日志并发送到复制通道（请参阅[第 13.4.1.3 节，“SET sql\_日志\_bin 声明”](set-sql-log-bin.html)）。

重要的

这`cache_sha2_password`身份验证插件是从 MySQL 8.0 创建的新用户的默认插件（有关详细信息，请参阅[第 6.4.1.2 节，“缓存 SHA-2 可插入身份验证”](caching-sha2-pluggable-authentication.html)）。要使用通过此插件进行身份验证的用户帐户连接到服务器，您必须按照中所述设置加密连接[第 17.3.1 节，“设置复制以使用加密连接”](replication-solutions-encrypted-connections.html)，或启用未加密连接以支持使用 RSA 密钥对进行密码交换。

设置用户帐户后，使用[`授予`](grant.html)语句授予附加权限，以使用户帐户能够进行您希望应用程序线程执行的数据库更改，例如更新服务器上保存的特定表。如果管理员需要在复制通道上手动执行任何这些事务，这些相同的权限使管理员能够使用该帐户。如果尝试了您未授予适当权限的意外操作，则该操作将被禁止，并且复制应用程序线程会因错误而停止。[第 17.3.3.1 节，“复制特权的特权\_检查\_用户帐号”](replication-privilege-checks-account.html)说明帐户需要哪些额外权限。例如，授予`priv_repl`用户帐户[`插入`](privileges-provided.html#priv_insert)将行添加到`客户`表`db1`，发出以下语句：

```
mysql> GRANT INSERT ON db1.cust TO 'priv_repl'@'%.example.com';
```

您分配`PRIVILEGE_CHECKS_USER`使用[`将复制源更改为`](change-replication-source-to.html)语句（来自 MySQL 8.0.23）或[`将主更改为`](change-master-to.html)语句（在 MySQL 8.0.23 之前）。如果复制正在运行，请发出[`停止复制`](stop-replica.html)（或在 MySQL 8.0.22 之前，[`停止奴隶`](stop-slave.html)） 之前[`将主更改为`](change-master-to.html)声明，以及[`开始复制`](start-replica.html)在它之后。强烈建议在以下情况下使用基于行的二进制日志记录`PRIVILEGE_CHECKS_USER`已设置，从 MySQL 8.0.19 开始您可以使用该语句设置`REQUIRE_ROW_FORMAT`强制执行。

当您重新启动复制通道时，将从该点开始应用对动态权限的检查。但是，在您重新加载授权表之前，静态全局权限在应用程序的上下文中是不活动的，因为对于连接的客户端，这些权限不会更改。要激活静态权限，请执行刷新权限操作。这可以通过发出一个[`刷新特权`](flush.html#flush-privileges)语句或通过执行[**mysqladmin 刷新权限**](mysqladmin.html)要么[**mysqladmin 重新加载**](mysqladmin.html)命令。

例如，在通道上启动权限检查`频道_1`在正在运行的副本上，发出以下语句：

```
mysql> STOP SLAVE FOR CHANNEL 'channel_1';
mysql> CHANGE MASTER TO
         PRIVILEGE_CHECKS_USER = 'priv_repl'@'%.example.com',
         REQUIRE_ROW_FORMAT = 1 FOR CHANNEL 'channel_1';
mysql> FLUSH PRIVILEGES;
mysql> START SLAVE FOR CHANNEL 'channel_1';

Or from MySQL 8.0.22 / 8.0.23:
mysql> STOP REPLICA FOR CHANNEL 'channel_1';
mysql> CHANGE REPLICATION SOURCE TO
         PRIVILEGE_CHECKS_USER = 'priv_repl'@'%.example.com',
         REQUIRE_ROW_FORMAT = 1 FOR CHANNEL 'channel_1';
mysql> FLUSH PRIVILEGES;
mysql> START REPLICA FOR CHANNEL 'channel_1';
```

如果您未指定通道且不存在其他通道，则该语句将应用于默认通道。的用户名和主机名`PRIVILEGE_CHECKS_USER`通道的帐户显示在性能架构中[`复制应用程序配置`](performance-schema-replication-applier-configuration-table.html)表中，它们被正确转义，因此可以直接复制到 SQL 语句中以执行单个事务。

什么时候`REQUIRE_ROW_FORMAT`为复制通道设置，复制应用程序不会创建或删除临时表，因此不会设置[`伪线程 ID`](server-system-variables.html#sysvar_pseudo_thread_id)会话系统变量。它不执行`加载数据文件`指令，因此不会尝试文件操作来访问或删除与数据加载相关的临时文件（记录为`Format_description_log_event`）。它不执行`英特瓦尔`,`兰德`， 和`USER_VAR`事件，用于为基于语句的复制重现客户端的连接状态。（一个例外是`USER_VAR`与执行的 DDL 查询相关联的事件。）它不执行在 DML 事务中记录的任何语句。如果复制应用程序在尝试排队或应用事务时检测到任何这些类型的事件，则不会应用该事件，并且复制会因错误而停止。

你可以设置`REQUIRE_ROW_FORMAT`对于复制通道，无论您是否设置`PRIVILEGE_CHECKS_USER`帐户。即使没有权限检查，设置此选项时实施的限制也会提高复制通道的安全性。您还可以指定`--要求行格式`使用时的选项[**mysqlbinlog**](mysqlbinlog.html), 以强制执行基于行的复制事件[**mysqlbinlog**](mysqlbinlog.html)输出。

**安全上下文。**默认情况下，当复制应用程序线程使用指定为`PRIVILEGE_CHECKS_USER`, 安全上下文是使用默认角色创建的，或者使用所有角色创建，如果[`activate_all_roles_on_login`](server-system-variables.html#sysvar_activate_all_roles_on_login)被设定为`在`.

您可以使用角色为用作帐户的帐户提供一般权限集`PRIVILEGE_CHECKS_USER`帐户，如下例所示。在这里，而不是授予[`插入`](privileges-provided.html#priv_insert)的特权`db1.cust`表直接到用户帐户，如前面的示例中一样，此权限被授予角色`priv_repl_role`随着[`REPLICATION_APPLIER`](privileges-provided.html#priv_replication-applier)特权。然后使用该角色将权限集授予两个用户帐户，现在这两个帐户都可以用作`PRIVILEGE_CHECKS_USER`帐户：

```
mysql> SET sql_log_bin = 0;
mysql> CREATE USER 'priv_repa'@'%.example.com'
                  IDENTIFIED BY 'password'
                  REQUIRE SSL;
mysql> CREATE USER 'priv_repb'@'%.example.com'
                  IDENTIFIED BY 'password'
                  REQUIRE SSL;
mysql> CREATE ROLE 'priv_repl_role';
mysql> GRANT REPLICATION_APPLIER TO 'priv_repl_role';
mysql> GRANT INSERT ON db1.cust TO 'priv_repl_role';
mysql> GRANT 'priv_repl_role' TO
                  'priv_repa'@'%.example.com',
                  'priv_repb'@'%.example.com';
mysql> SET DEFAULT ROLE 'priv_repl_role' TO
                  'priv_repa'@'%.example.com',
                  'priv_repb'@'%.example.com';
mysql> SET sql_log_bin = 1;
```

请注意，当复制应用程序线程创建安全上下文时，它会检查`PRIVILEGE_CHECKS_USER`账户，但不进行密码验证，不进行与账户管理相关的检查，如检查账户是否被锁定。创建的安全上下文在复制应用程序线程的生命周期内保持不变。

**局限性。**仅在 MySQL 8.0.18 中，如果副本[**mysqld**](mysqld.html)发出后立即重新启动[`重置副本`](reset-replica.html)语句（由于意外的服务器退出或故意重新启动），`PRIVILEGE_CHECKS_USER`帐户设置，保存在`mysql.slave_relay_log_info`表丢失，必须重新指定。当您在该版本中使用权限检查时，请始终在重新启动后验证它们是否到位，并在需要时重新指定它们。从 MySQL 8.0.19 开始，`PRIVILEGE_CHECKS_USER`在这种情况下会保留帐户设置，因此会从表中检索并重新应用于通道。
