MySQL 中 GRANT 操作会引起复制中断吗?

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: GRANT 操作并不是一个原子性操作,不管执行成功与否,都会触发一个隐式重载授权表的行为。在生产环境中需要规范用户创建及授权的操作,不推荐使用 DML 语句去直接变更 mysql.user 表,可能会引发其他的问题,若使用了 DML 语句进行变更,需要手工执行 flush privileges。

问题背景

客户反馈,某业务测试环境的数据库主从同步断开。

登录到从库,执行 show slave status\G,发现 sql 线程没有工作了,具体报错为:

LAST_ERROR_MUMBER: 1410
LAST_ERROR_MESSAGE: Worker 1 failed executing transaction 'c593bdc6-cd10-11ec-ac44-0050568a0cc2:2003275' at master log mysql-bin.00187, end_log_post 142 'You are not allowed to create a user with GRANT' on query. Default database: 'mysql'. Query: 'GRANT ALL PRIVILIEGES ON *.* TO 'p-dms-all'@100.104.%''

从提示可以看出是 GRANT 操作失败导致 sql 线程断开了。

经过与其他运维同事的沟通,了解到客户执行了创建用户并授权的操作。由于数据库中本身有一个未使用的用户,所以选择直接对 mysql.user 表的用户数据做 UPDATE 操作实现授权,从 MySQL 操作日志记录也可以看到如下操作:

尝试执行 start slave,从库的 sql 线程就已经正常工作了。GRANT 的操作也已经正常回放了。

也许你好奇这个过程中到底发生了什么,下面通过复现验证并解释该现象。

本地复现

现有一套 MySQL 8.0 的主从,数据库中已存在只读用户 test@'10.186.%'

mysql> show grants for test@'10.186.%';
+------------------------------------------+
| Grants for test@10.186.%                 |
+------------------------------------------+
| GRANT SELECT ON *.* TO `test`@`10.186.%` |
+------------------------------------------+
1 row in set (0.00 sec)

主库更改 test@'10.186.%' 用户的 host 并进行授权操作。

mysql> update mysql.user set host='%' where user='test';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> grant all on *.* to test@'%';
ERROR 1410 (42000): You are not allowed to create a user with GRANT
mysql> grant all on *.* to test@'%';
Query OK, 0 rows affected (0.00 sec)

可以看到第一次 GRANT 操作失败了,再执行第二次可以成功。此时查看从库的复制状态,从库的 sql 线程已断开,稳定复现该问题。

mysql> show slave status\G
*************************** 1. row ***************************
 Last_Errno: 1410
 Last_Error: Coordinator stopped because there were error(s) in the worker(s). 
 The most recent failure being: Worker 1 failed executing transaction 
 '59c87cdc-9a47-11ee-b06e-02000aba394f:149931' at master log mysql-bin.000001, 
 end_log_pos 68067966. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any.
mysql> select * from performance_schema.replication_applier_status_by_worker limit 1\G
*************************** 1. row ***************************
LAST_ERROR_MESSAGE: Worker 1 failed executing transaction 
'59c87cdc-9a47-11ee-b06e-02000aba394f:149931' at master log mysql-bin.000001, 
end_log_pos 68067966; Error 'You are not allowed to create a user with GRANT' on query. 
Default database: ''. Query: 'GRANT ALL PRIVILEGES ON *.* TO 'test'@'%''

官方说明

  • 如果使用账户管理语句更改授权表,服务器会注意到这些更改并立即将授权表加载到内存中。例如 GRANT,REVOKE,SET PASSWORD,RENAME USER 等操作。
  • 如果使用 INSERTUPDATEDELETE 等语句直接修改授权表(不推荐),这些更改并不会加载到内存,除非告诉服务器重新加载授权表或者重启数据库。
  • flush-privileges 操作可以让服务器重新加载授权表。

官方文档的这段描述可以解释为什么在 UPDATE 操作之后,执行两次 GRANT 才能成功。

分析过程

UPDATE 操作之后并未将授权表的更改加载到内存,此时内存中并没有 test@'%' 用户,所以第一次 GRANT 操作失败了。

虽然返回执行失败了,但是第一次 GRANT 执行实际有将 UPDATE 的变更加载到内存(可以理解是隐式执行了 flush privileges,不过 flush privileges 并没有记录到 binlog 日志中),所以第二次 GRANT 执行成功,从库回放到 GRANT 时复制中断重新启动复制即可恢复也是这个逻辑。

GRANT 操作是不是原子性?

那么问题来了,从复现的现象来看,第一个 GRANT 操作虽然执行返回错误,但是实际上已进行了重载授权表的操作。所以,GRANT 操作失败后并没有完全回滚,看来 GRANT 操作不是一个原子性操作,可以来验证一下。

实验验证

总结

  1. GRANT 操作并不是一个原子性操作,不管执行成功与否,都会触发一个隐式重载授权表的行为。
  2. 在生产环境中需要规范用户创建及授权的操作,不推荐使用 DML 语句去直接变更 mysql.user 表,可能会引发其他的问题,若使用了 DML 语句进行变更,
  3. 需要手工执行 flush privileges
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5月前
|
JavaScript 关系型数据库 MySQL
创建nodejs项目并接入mysql,完成用户相关的增删改查的详细操作
创建nodejs项目并接入mysql,完成用户相关的增删改查的详细操作
67 0
|
6月前
|
关系型数据库 MySQL
【mysql技巧】如何在这个mysql语句执行前加个前提,也就是只有表里没有相同数据才进行添加插入操作
【mysql技巧】如何在这个mysql语句执行前加个前提,也就是只有表里没有相同数据才进行添加插入操作
39 1
|
5月前
|
存储 关系型数据库 文件存储
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
51 2
|
5月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版操作报错合集之从mysql读数据写到hive报错,是什么原因
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
消息中间件 关系型数据库 MySQL
实时计算 Flink版操作报错合集之运行mysql to doris pipeline时报错,该如何排查
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
消息中间件 关系型数据库 MySQL
实时计算 Flink版操作报错合集之整库同步mysql到starRock提交任务异常,该如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
SQL 关系型数据库 MySQL
「Python入门」python操作MySQL和SqlServer
**摘要:** 了解如何使用Python的pymysql模块与MySQL数据库交互。首先,通过`pip install pymysql`安装模块。pymysql提供与MySQL的连接功能,例如创建数据库连接、执行SQL查询。在设置好MySQL环境后,使用`pymysql.connect()`建立连接,并通过游标执行SQL(如用户登录验证)。注意防止SQL注入,使用参数化查询。增删改操作需调用`conn.commit()`来保存更改。pymssql模块类似,但导入和连接对象创建略有不同。
67 0
「Python入门」python操作MySQL和SqlServer
|
5月前
|
SQL 存储 关系型数据库
|
6月前
|
关系型数据库 MySQL 数据库
『Django』模型入门教程-操作MySQL
一个后台如果没有数据库可以说废了一半。日常开发中大多数时候都在与数据库打交道。Django 为我们提供了一种更简单的操作数据库的方式。 在 Django 中,模型(Model)是用来定义数据库结构的类。每个模型类通常对应数据库中的一个表,类的属性对应表中的列。通过定义模型,Django 的 ORM(Object-Relational Mapping)可以将 Python 对象映射到数据库表,并提供一套 API 来进行数据库操作。 本文介绍模型的用法。
|
5月前
|
SQL Java 数据库
MySQL设计规约问题之为什么应尽量避免使用子查询,而可以考虑将其优化为join操作
MySQL设计规约问题之为什么应尽量避免使用子查询,而可以考虑将其优化为join操作