复制权限检查
默认情况下,当已经被另一个服务器接受的事务应用于复制从属或组成员时,MySQL复制(包括组复制)不执行特权检查。从MySQL 8.0.18开始,您可以创建一个具有适当特权的用户帐户,以应用通常在通道上复制的事务,并PRIVILEGE_CHECKS_USER
使用一条CHANGE MASTER TO
语句将该用户帐户指定为复制应用程序的帐户。然后,MySQL将根据用户帐户的权限检查每个事务,以验证您已授权该通道的操作。管理员也可以安全地使用该帐户从mysqlbinlog应用或重新应用事务输出,例如从通道上的复制错误中恢复。
PRIVILEGE_CHECKS_USER
帐户的使用有助于保护复制通道,以防止未经授权或意外使用特权或不需要的操作。PRIVILEGE_CHECKS_USER
在以下情况下,该帐户可提供额外的安全保护:
- 您正在组织网络上的服务器实例与另一个网络上的服务器实例(例如云服务提供商提供的实例)之间进行复制。
- 您希望将多个本地或异地部署作为单独的单元进行管理,而又不给所有部署一个管理员帐户特权。
- 您希望拥有一个管理员帐户,该帐户使管理员能够仅执行与复制通道及其复制的数据库直接相关的操作,而不要对服务器实例具有广泛的特权。
PRIVILEGE_CHECKS_USER
为复制通道指定帐户时,还可以使用CHANGE MASTER TO
语句设置REQUIRE_ROW_FORMAT
选项(可从MySQL 8.0.19获得)以使通道仅接受基于行的复制事件。当REQUIRE_ROW_FORMAT
设置,则必须使用基于行的二进制日志(binlog_format=ROW
在主)。在MySQL 8.0.18 REQUIRE_ROW_FORMAT
中不可用,但是仍然强烈建议对安全复制通道使用基于行的二进制日志记录。使用基于语句的二进制日志记录,需要某些管理员级别的权限才能成功执行事务。
您授予REPLICATION_APPLIER
特权以使用户帐户显示为PRIVILEGE_CHECKS_USER
复制应用程序线程的权限,并执行BINLOG
mysqlbinlog 使用的内部使用语句。该PRIVILEGE_CHECKS_USER
帐户的用户名和主机名必须遵循“指定帐户名”中所述的语法,并且该用户不得为匿名用户(用户名为空)或CURRENT_USER
。要创建一个新帐户,请使用CREATE USER
。要授予此帐户REPLICATION_APPLIER
特权,请使用以下GRANT
语句。例如,要创建一个用户帐户priv_repl
,管理员可以从该帐户中的任何主机手动使用该帐户example.com
域,并且需要加密的连接,请发出以下语句:
mysql>SET sql_log_bin = 0; mysql>CREATE USER 'priv_repl'@'%.example.com'IDENTIFIED BY 'password'REQUIRE SSL ; mysql>GRANT REPLICATION_APPLIERON *.*TO 'priv_repl'@'%.example.com'; mysql>SET sql_log_bin = 1;
使用这些SET sql_log_bin
语句是为了使帐户管理语句不会添加到二进制日志中,也不会发送到复制通道(请参见“ SET sql_log_bin语句”)。
重要
caching_sha2_password
对于从MySQL 8.0创建的新用户,身份验证插件是默认的(有关详细信息,请参见“缓存SHA-2可插入身份验证”)。要使用通过此插件进行身份验证的用户帐户连接到服务器,必须按照“设置复制以使用加密的连接”中所述设置加密的连接,或者启用未加密的连接以支持密码交换使用RSA密钥对。
设置用户帐户后,使用该GRANT
语句授予其他特权,以使用户帐户能够执行希望应用程序线程执行的数据库更改,例如更新服务器上保存的特定表。如果管理员需要在复制通道上手动执行任何这些事务,则这些相同的特权使管理员可以使用该帐户。如果尝试执行您未授予其适当特权的意外操作,则该操作将被禁止,并且复制应用程序线程会因错误而停止。“复制PRIVILEGE_CHECKS_USER帐户的特权”说明该帐户需要哪些其他特权。例如,要授予priv_repl
用户帐户INSERT
向中的cust
表添加行的权限db1
,请发出以下语句:
mysql>GRANT INSERT ON db1.custTO 'priv_repl'@'%.example.com';
您可以PRIVILEGE_CHECKS_USER
使用CHANGE MASTER TO
语句为复制通道分配帐户。强烈建议在PRIVILEGE_CHECKS_USER
设置时使用基于行的二进制日志记录,并且从MySQL 8.0.19开始,您可以使用语句REQUIRE_ROW_FORMAT
来强制执行此操作。如果复制正在运行,请STOP SLAVE
在CHANGE MASTER TO
语句之前和START SLAVE
之后发出。例如,要channel_1
在正在运行的复制从属服务器上的通道上启动特权检查,请发出以下语句:
mysql>STOP SLAVE FOR CHANNEL 'channel_1'; mysql>CHANGE MASTER TO PRIVILEGE_CHECKS_USER = 'priv_repl'@'%.example.com',REQUIRE_ROW_FORMAT = 1FOR CHANNEL 'channel_1'; mysql>START SLAVE FOR CHANNEL 'channel_1';
重新启动复制通道时,从那时起将应用特权检查。如果您未指定通道并且不存在其他通道,则该语句将应用于默认通道。PRIVILEGE_CHECKS_USER
通道帐户的用户名和主机名显示在“性能模式”replication_applier_configuration
表中,在此处正确进行了转义,因此可以将它们直接复制到SQL语句中以执行单个事务。
当REQUIRE_ROW_FORMAT
被设定为一个复制的信道,则复制施加不创建或删除临时表,因此不设置pseudo_thread_id
会话系统变量。它不执行LOAD DATA INFILE
指令,因此不会尝试文件操作来访问或删除与数据加载相关联的临时文件(记录为Format_description_log_event
)。它不执行INTVAR
,RAND
和USER_VAR
事件,这些事件用于为基于语句的复制重现客户端的连接状态。(一个例外是USER_VAR
与DDL查询关联的事件(已执行)。它不执行DML事务中记录的任何语句。如果复制请求者在尝试排队或应用事务时检测到任何此类事件,则不应用该事件,并且复制会因错误而停止。
REQUIRE_ROW_FORMAT
无论是否设置PRIVILEGE_CHECKS_USER
帐户,都可以设置复制通道。设置此选项时实施的限制即使没有特权检查也可以提高复制通道的安全性。您还--require-row-format
可以在使用mysqlbinlog时指定该选项,以在mysqlbinlog输出中强制执行基于行的复制事件。
安全上下文。默认情况下,使用指定为的用户帐户启动复制应用程序线程时PRIVILEGE_CHECKS_USER
,将使用默认角色创建安全上下文,或者将所有角色(如果activate_all_roles_on_login
设置为)创建安全上下文ON
。您可以使用角色向用作PRIVILEGE_CHECKS_USER
帐户的帐户提供常规特权集,如以下示例所示,该REPLICATION_APPLIER
特权集将特权与特权一起SESSION_VARIABLES_ADMIN
授予:
mysql>SET sql_log_bin = 0; mysql>CREATE USER 'priv_repl'@'%.example.com'IDENTIFIED BY 'password'REQUIRE SSL ; mysql>CREATE ROLE 'priv_repl_role'; mysql>GRANT REPLICATION_APPLIER,SESSION_VARIABLES_ADMINTO 'priv_repl_role'; mysql>GRANT 'priv_repl_role'TO 'priv_repl'@'%.example.com'; mysql>SET DEFAULT ROLE 'priv_repl_role'TO 'priv_repl'@'%.example.com'; mysql>SET sql_log_bin = 1;
请注意,当复制应用程序线程创建安全上下文时,它将检查PRIVILEGE_CHECKS_USER
帐户的特权,但不执行密码验证,也不执行与帐户管理有关的检查,例如检查帐户是否被锁定。在复制应用程序线程的生存期内,创建的安全上下文将保持不变。
局限性。仅在MySQL 8.0.18中,如果从属mysqld在发出一条RESET SLAVE
语句后立即重新启动(由于服务器崩溃或有意重新启动),PRIVILEGE_CHECKS_USER
则mysql.slave_relay_log_info
表中保存的帐户设置将丢失,必须重新指定。当您在该发行版中使用特权检查时,请始终在重新启动后验证它们是否就位,并在需要时重新指定它们。在MySQL 8.0.19中,PRIVILEGE_CHECKS_USER
在这种情况下保留了帐户设置,因此可以从表中检索帐户设置并将其重新应用到通道。
复制权限PRIVILEGE_CHECKS_USER帐户
被指定为PRIVILEGE_CHECKS_USER
复制通道帐户的用户帐户必须具有REPLICATION_APPLIER
特权,否则复制应用程序线程将不会启动。如“复制特权检查”中所述,该帐户需要其他特权,这些特权足以应用复制通道上预期的所有预期事务。仅在执行相关事务时才检查这些特权。
对于使用帐户binlog_format=ROW
保护的复制通道,强烈建议使用基于行的二进制日志记录()PRIVILEGE_CHECKS_USER
。使用基于语句的二进制日志记录,需要某些管理员级别的权限才能成功执行事务。从MySQL 8.0.19起,该REQUIRE_ROW_FORMAT
设置可以应用于安全通道,从而限制了通道执行需要这些特权的事件。
该REPLICATION_APPLIER
特权显式或隐式允许PRIVILEGE_CHECKS_USER
帐户执行复制线程需要执行的以下操作:
- 设置系统变量的值
gtid_next
,original_commit_timestamp
,original_server_version
,immediate_server_version
,和pseudo_slave_mode
,在执行交易时应用适当的元数据和行为。 - 执行内部使用
BINLOG
语句以应用mysqlbinlog输出,前提是该帐户还具有对这些语句中的表和操作的许可权。 - 更新系统表
mysql.gtid_executed
,mysql.slave_relay_log_info
,mysql.slave_worker_info
,和mysql.slave_master_info
,更新复制元数据。(如果事件为其他目的显式访问这些表,则必须在表上授予适当的特权。) - 应用二进制日志
Table_map_log_event
,该日志提供表元数据,但不进行任何数据库更改。
该PRIVILEGE_CHECKS_USER
帐户需要SESSION_VARIABLES_ADMIN
特权才能在sql_require_primary_key
会话期间更改系统变量的值以执行复制操作。该特权还允许该帐户应用使用该选项创建的mysqlbinlog输出--disable-log-bin
。
如果使用表加密,则table_encryption_privilege_check
系统变量设置为ON
,并且任何事件中涉及的表空间的加密设置都与应用服务器的默认加密设置(由default_table_encryption
系统变量指定)不同,该PRIVILEGE_CHECKS_USER
帐户需要TABLE_ENCRYPTION_ADMIN
特权才能覆盖默认的加密设置。强烈建议您不要授予此特权。相反,请确保复制从属服务器上的默认加密设置与它复制的表空间的加密状态相匹配,并且复制组成员具有相同的默认加密设置,因此不需要特权。
为了从中继日志执行特定的复制事务,或根据需要从mysqlbinlog输出执行事务,该PRIVILEGE_CHECKS_USER
帐户必须具有以下特权:
- 对于以行格式记录的行插入(以记录
Write_rows_log_event
),INSERT
具有相关表上的特权。 - 对于以行格式记录的行更新(以记录
Update_rows_log_event
),UPDATE
具有相关表上的特权。 - 对于以行格式登录的行删除(以记录
Delete_rows_log_event
),DELETE
具有相关表上的特权。
如果正在使用基于语句的二进制日志记录(不建议在PRIVILEGE_CHECKS_USER
帐户中使用),对于以语句格式(以记录的)的事务控制语句(例如BEGIN
or COMMIT
或DML Query_log_event
),该PRIVILEGE_CHECKS_USER
帐户需要特权来执行包含的语句在事件中。
如果LOAD DATA
需要在复制通道上执行操作,请使用基于行的二进制日志记录(binlog_format=ROW
)。使用这种日志记录格式,FILE
不需要特权来执行事件,因此请不要给该PRIVILEGE_CHECKS_USER
帐户特权。强烈建议对使用PRIVILEGE_CHECKS_USER
帐户保护的复制通道使用基于行的二进制日志记录。如果REQUIRE_ROW_FORMAT
为通道设置了,则需要基于行的二进制日志记录。的Format_description_log_event
,它会删除创建的临时文件LOAD DATA
的事件,在没有权限检查处理。有关更多信息,请参见“复制功能”。
如果将init_slave
系统变量设置为指定在SQL线程启动时要执行的一个或多个SQL语句,则该PRIVILEGE_CHECKS_USER
帐户必须具有执行这些语句所需的特权。
建议你从来没有给任何ACL权限的PRIVILEGE_CHECKS_USER
帐户,包括CREATE USER
,CREATE ROLE
,DROP ROLE
,和GRANT OPTION
,并且不允许帐户更新mysql.user
表。拥有这些特权,该帐户可用于在服务器上创建或修改用户帐户。为避免在主服务器上发出的ACL语句被复制到安全通道中执行(在缺少这些特权的情况下它们将失败),您可以SET sql_log_bin = 0
在所有ACL语句和SET sql_log_bin = 1
在它们之后,忽略主数据库二进制日志中的语句。另外,您可以在执行所有ACL语句之前设置专用的当前数据库,并使用复制过滤器(--binlog-ignore-db
)过滤从属服务器上的该数据库。
特权检查组复制通道
从MySQL 8.0.19开始,除了保护异步和半同步复制,您还可以选择使用一个PRIVILEGE_CHECKS_USER
帐户来保护组复制使用的两个复制应用程序线程。group_replication_applier
每个组成员上的线程用于应用组的事务,并且group_replication_recovery
当成员加入或重新加入组时,作为分布式恢复的一部分,每个组成员上的线程用于从二进制日志进行状态转移。
要保护这些线程之一,请停止“组复制”,然后发出CHANGE MASTER TO
带有PRIVILEGE_CHECKS_USER
选项的语句,指定group_replication_applier
或group_replication_recovery
作为通道名称。例如:
mysql>STOP GROUP_REPLICATION ; mysql>CHANGE MASTER TO PRIVILEGE_CHECKS_USER = 'gr_repl'@'%.example.com'FOR CHANNEL 'group_replication_recovery'; mysql>START GROUP_REPLICATION ;
对于组复制通道,该REQUIRE_ROW_FORMAT
设置会在创建通道时自动启用,并且无法禁用,因此您无需指定此设置。
重要在MySQL 8.0.19中,请确保在组复制运行时不发出
CHANGE MASTER TO
带有PRIVILEGE_CHECKS_USER
选项的语句。此操作将导致清除通道的中继日志文件,这可能会导致丢失已在中继日志中接收和排队但尚未应用的事务。
如果在组复制中将远程克隆操作用于分布式恢复(请参见“克隆分布式恢复”),则从MySQL 8.0.19开始,将PRIVILEGE_CHECKS_USER
来自施主的帐户和设置克隆到加入成员。如果将加入成员设置为在启动时启动组复制,它将自动使用该帐户作为适当的复制通道。
在MySQL 8.0.18中,由于许多限制,建议您不要使用PRIVILEGE_CHECKS_USER
具有组复制通道的帐户。
从失败的复制特权检查中恢复
如果对该PRIVILEGE_CHECKS_USER
帐户的特权检查失败,则不会执行该事务,并且该通道的复制将停止。错误和上次应用的事务的详细信息记录在“性能模式”replication_applier_status_by_worker
表中。请按照以下步骤从错误中恢复:
- 标识导致错误的复制事件,并验证是否是预期事件并来自可信来源。您可以使用mysqlbinlog检索和显示错误发生前后记录的事件。有关执行此操作的说明,请参见“使用二进制日志进行时间点(增量)恢复”。
- 如果复制的事件不是预期的,或者不是来自已知的受信任来源,请调查原因。如果您可以确定事件发生的原因并且没有安全方面的考虑,请按照以下说明继续修复错误。
- 如果
PRIVILEGE_CHECKS_USER
应该允许该帐户执行事务,但配置错误,请为该帐户授予缺少的特权,然后重新启动该通道的复制。 - 如果需要执行事务并且您已验证它是可信的,但是该
PRIVILEGE_CHECKS_USER
帐户通常不具有此特权,则可以PRIVILEGE_CHECKS_USER
暂时将所需的特权授予该帐户。应用复制的事件后,请从帐户中删除特权,并采取任何必要的步骤来确保该事件在可避免的情况下不会再次发生。 - 如果事务是仅应在主服务器上而不是从服务器上执行的管理操作,或者仅应在单个复制组成员上执行的管理操作,请在停止复制的服务器上跳过该事务,然后发出
START SLAVE
重新启动通道上的复制。为避免将来出现这种情况,您可以SET sql_log_bin = 0
在它们之前和SET sql_log_bin = 1
之后发布这样的管理声明,这样它们就不会登录到主数据库中。 - 如果事务是不应在主服务器或从服务器上进行的DDL或DML语句,请在停止复制的服务器上跳过该事务,在最初发生事务的服务器上手动撤消该事务,然后
START SLAVE
重新启动复制的问题。
要跳过事务,如果正在使用GTID,请提交具有失败事务的GTID的空事务,例如:
SET GTID_NEXT='aaa-bbb-ccc-ddd:N';BEGIN ;COMMIT ;SET GTID_NEXT='AUTOMATIC';
如果未使用GTID,请发出SET GLOBAL sql_slave_skip_counter
语句以跳过事件,如“ SET GLOBAL sql_slave_skip_counter语句”中所述。