commit 040e3a009503c66ec26995a6a75e473cb74fd036 Author: GAO Xiaoxin Date: Thu Apr 7 19:04:06 2022 +0800 Bug #106942 alter user may lead replication broken with error 1396 Alter user may lead replication broken with error 1396, see the following case: 1. setup a replication m1->s1 with RBR 2. Init test user on m1: 1) create user u1@'%' identified with 'mysql_native_password'; 2) grant all on *.* to u1@'%'; 3. Modify the mysql.user table to set a invalid authentication_string for test user on m1: 1) update mysql.user set authentication_string=MD5("password") where user="u1"; 2) flush privileges; 4. Reset authentication_string to empty for test user on m1: 1) update mysql.user set authentication_string="" where user="u1"; 5. Do the alter user twice on m1: 1) alter user u1@'%' identified with mysql_native_password by 'abc123' password expire never; // this one will fail with "ERROR 1396 (HY000): Operation ALTER USER failed for 'u1'@'%'" 2) alter user u1@'%' identified with mysql_native_password by 'abc123' password expire never; // this one will success 6. check slave status on s1, we will see the following error: Last_SQL_Errno: 1396, Operation ALTER USER failed for... The reason is: 1. The first fail alter user command implicit to the reload_acl_caches, just like the "flush privileges". 2. But this fail alter user command write nothing to the binlog. And the second alter user command, which success, will be written to the binlog. 3, So the slave only see one alter user, which will execute fail just like the first alter user on m1. For fix: Cause the alter user command may invoke the reload_acl_caches if it execute fail, so it is better to invoke the reload_acl_caches at the beginning of mysql_alter_user. So the alter usr will always reload_acl_caches, the behavior of alter user is more predicatable. diff --git a/sql/auth/.sql_user.cc.swp b/sql/auth/.sql_user.cc.swp index 282ae14..17c9612 100644 Binary files a/sql/auth/.sql_user.cc.swp and b/sql/auth/.sql_user.cc.swp differ diff --git a/sql/auth/sql_user.cc b/sql/auth/sql_user.cc index a08e64f..c6df115 100644 --- a/sql/auth/sql_user.cc +++ b/sql/auth/sql_user.cc @@ -3283,6 +3283,7 @@ bool mysql_alter_user(THD *thd, List &list, bool if_exists) { std::vector server_challenge; DBUG_TRACE; + reload_acl_caches(thd, false);//always do the reload acl caches before alter user /* This statement will be replicated as a statement, even when using row-based replication. The binlog state will be cleared here to