diff --git a/mysql-test/suite/percona/r/bug_ps11143_threadpool_auth_shutdown.result b/mysql-test/suite/percona/r/bug_ps11143_threadpool_auth_shutdown.result new file mode 100644 index 000000000000..4331e438c1c0 --- /dev/null +++ b/mysql-test/suite/percona/r/bug_ps11143_threadpool_auth_shutdown.result @@ -0,0 +1,11 @@ +# +# Verify auth callback drains before plugin deinit with threadpool +# +# restart:--thread-handling=pool-of-threads --thread-pool-size=2 --thread-pool-max-threads=4 +CREATE USER tp_user@127.0.0.1 IDENTIFIED WITH caching_sha2_password BY 'tp_pwd'; +SET GLOBAL debug = "+d,auth_plugin_before_callback_sync"; +1 +1 +SET DEBUG_SYNC='now WAIT_FOR auth_plugin_before_callback_entered TIMEOUT 30'; +# restart +DROP USER IF EXISTS tp_user@127.0.0.1; diff --git a/mysql-test/suite/percona/t/bug_ps11143_threadpool_auth_shutdown.test b/mysql-test/suite/percona/t/bug_ps11143_threadpool_auth_shutdown.test new file mode 100644 index 000000000000..1e78fd1f41c4 --- /dev/null +++ b/mysql-test/suite/percona/t/bug_ps11143_threadpool_auth_shutdown.test @@ -0,0 +1,45 @@ +--source include/not_windows.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--echo # +--echo # Verify auth callback drains before plugin deinit with threadpool +--echo # + +--let $restart_parameters=restart:--thread-handling=pool-of-threads --thread-pool-size=2 --thread-pool-max-threads=4 +--source include/restart_mysqld.inc +--source include/have_pool_of_threads.inc + +CREATE USER tp_user@127.0.0.1 IDENTIFIED WITH caching_sha2_password BY 'tp_pwd'; + +SET GLOBAL debug = "+d,auth_plugin_before_callback_sync"; + +--let $mysqld_pid_file=`SELECT @@GLOBAL.pid_file` + +--let $output_file= $MYSQLTEST_VARDIR/tmp/bug_ps11143_mysql_output +--let $pid_file= $MYSQLTEST_VARDIR/tmp/bug_ps11143_mysql_pid +--let $sql_file= $MYSQLTEST_VARDIR/tmp/bug_ps11143_query.sql +--write_file $sql_file +SELECT 1; +EOF +--let $command= $MYSQL +--let $command_opt= --protocol=tcp --host=127.0.0.1 --port=$MASTER_MYPORT --user=tp_user --password=tp_pwd < $sql_file +--let $redirect_stderr= 1 +--source include/start_proc_in_background.inc + +SET DEBUG_SYNC='now WAIT_FOR auth_plugin_before_callback_entered TIMEOUT 30'; + +--source include/expect_crash.inc +exec kill -TERM `cat $mysqld_pid_file`; + +--source include/wait_until_disconnected.inc +--source include/wait_proc_to_finish.inc + +--let $restart_parameters= +--source include/start_mysqld.inc + +DROP USER IF EXISTS tp_user@127.0.0.1; + +--remove_file $pid_file +--remove_file $output_file +--remove_file $sql_file diff --git a/sql/auth/acl_table_user.cc b/sql/auth/acl_table_user.cc index b3c3462159a2..2c401104c119 100644 --- a/sql/auth/acl_table_user.cc +++ b/sql/auth/acl_table_user.cc @@ -47,6 +47,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sql/auth/auth_acls.h" /* ACLs */ #include "sql/auth/auth_common.h" /* User_table_schema, ... */ #include "sql/auth/auth_internal.h" /* acl_print_ha_error */ +#include "sql/auth/auth_plugin_shutdown.h" #include "sql/auth/partial_revokes.h" #include "sql/auth/sql_auth_cache.h" /* global_acl_memory */ #include "sql/auth/sql_authentication.h" /* Cached_authentication_plugins */ @@ -1656,6 +1657,13 @@ bool Acl_table_user_reader::read_plugin_info( if (native_plugin) { const uint password_len = password ? strlen(password) : 0; st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(native_plugin)->info; + Auth_plugin_operation_guard op_guard; + if (!op_guard) { + LogErr(WARNING_LEVEL, ER_AUTHCACHE_USER_IGNORED_INVALID_PASSWORD, + user.user ? user.user : "", + user.host.get_host() ? user.host.get_host() : ""); + return true; + } if (auth->validate_authentication_string(password, password_len) == 0) { // auth_string takes precedence over password if (user.credentials[PRIMARY_CRED].m_auth_string.length == 0) { @@ -1704,10 +1712,11 @@ bool Acl_table_user_reader::read_plugin_info( my_plugin_lock_by_name(nullptr, user.plugin, MYSQL_AUTHENTICATION_PLUGIN); if (plugin) { st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(plugin)->info; - if (auth->validate_authentication_string( - const_cast( - user.credentials[PRIMARY_CRED].m_auth_string.str), - user.credentials[PRIMARY_CRED].m_auth_string.length)) { + Auth_plugin_operation_guard op_guard; + if (!op_guard || auth->validate_authentication_string( + const_cast( + user.credentials[PRIMARY_CRED].m_auth_string.str), + user.credentials[PRIMARY_CRED].m_auth_string.length)) { LogErr(WARNING_LEVEL, ER_AUTHCACHE_USER_IGNORED_INVALID_PASSWORD, user.user ? user.user : "", user.host.get_host() ? user.host.get_host() : ""); @@ -1921,7 +1930,9 @@ bool Acl_table_user_reader::read_user_attributes(ACL_USER &user) { if (plugin) { st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(plugin)->info; - if (auth->validate_authentication_string( + Auth_plugin_operation_guard op_guard; + if (!op_guard || + auth->validate_authentication_string( const_cast( user.credentials[SECOND_CRED].m_auth_string.str), user.credentials[SECOND_CRED].m_auth_string.length)) { diff --git a/sql/auth/auth_plugin_shutdown.h b/sql/auth/auth_plugin_shutdown.h new file mode 100644 index 000000000000..4a47f4003fe8 --- /dev/null +++ b/sql/auth/auth_plugin_shutdown.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2026, Percona LLC and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is designed to work with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have either included with + the program or referenced in the documentation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef AUTH_PLUGIN_SHUTDOWN_INCLUDED +#define AUTH_PLUGIN_SHUTDOWN_INCLUDED + +bool begin_auth_plugin_operation(); +void end_auth_plugin_operation(); +void start_auth_plugin_shutdown_and_wait(); + +class Auth_plugin_operation_guard { + public: + Auth_plugin_operation_guard() + : m_has_operation(begin_auth_plugin_operation()) {} + + ~Auth_plugin_operation_guard() { + if (m_has_operation) end_auth_plugin_operation(); + } + + bool has_operation() const { return m_has_operation; } + explicit operator bool() const { return m_has_operation; } + + private: + bool m_has_operation; +}; + +#endif // AUTH_PLUGIN_SHUTDOWN_INCLUDED diff --git a/sql/auth/sha2_password.cc b/sql/auth/sha2_password.cc index 21dabb1c8c3c..06883ef6687e 100644 --- a/sql/auth/sha2_password.cc +++ b/sql/auth/sha2_password.cc @@ -76,6 +76,8 @@ struct SYS_VAR; #include +extern sha2_password::Caching_sha2_password *g_caching_sha2_password; + char *caching_sha2_rsa_private_key_path; char *caching_sha2_rsa_public_key_path; bool caching_sha2_auto_generate_rsa_keys = true; @@ -924,6 +926,7 @@ static char perform_full_authentication = '\4'; static int caching_sha2_password_authenticate(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) { DBUG_TRACE; + uchar *pkt; int pkt_len; char scramble[SCRAMBLE_LENGTH + 1]; @@ -1126,9 +1129,9 @@ static int caching_sha2_password_authenticate(MYSQL_PLUGIN_VIO *vio, */ int caching_sha2_password_generate(char *outbuf, unsigned int *buflen, - const char *inbuf, - unsigned int inbuflen) { + const char *inbuf, unsigned int inbuflen) { DBUG_TRACE; + std::string digest; const std::string source(inbuf, inbuflen); std::string random; @@ -1186,6 +1189,7 @@ int caching_sha2_password_generate(char *outbuf, unsigned int *buflen, static int caching_sha2_password_validate(char *const inbuf, unsigned int buflen) { DBUG_TRACE; + const std::string serialized_string(inbuf, buflen); if (g_caching_sha2_password->validate_hash(serialized_string)) return 1; return 0; @@ -1243,10 +1247,12 @@ static int caching_sha2_authentication_init(MYSQL_PLUGIN plugin_ref) { static int caching_sha2_authentication_deinit(void *arg [[maybe_unused]]) { DBUG_TRACE; - if (g_caching_sha2_password) { + + if (g_caching_sha2_password != nullptr) { delete g_caching_sha2_password; g_caching_sha2_password = nullptr; } + return 0; } @@ -1391,6 +1397,7 @@ static SHOW_VAR caching_sha2_password_status_variables[] = { static int sha2_cache_cleaner_notify(MYSQL_THD, mysql_event_class_t event_class, const void *event) { DBUG_TRACE; + if (event_class == MYSQL_AUDIT_AUTHENTICATION_CLASS) { const struct mysql_event_authentication *authentication_event = (const struct mysql_event_authentication *)event; diff --git a/sql/auth/sql_auth_cache.cc b/sql/auth/sql_auth_cache.cc index 0356203ccf8f..c6a490986ed2 100644 --- a/sql/auth/sql_auth_cache.cc +++ b/sql/auth/sql_auth_cache.cc @@ -50,6 +50,7 @@ #include "sql/auth/auth_acls.h" #include "sql/auth/auth_common.h" // ACL_internal_schema_access #include "sql/auth/auth_internal.h" // auth_plugin_is_built_in +#include "sql/auth/auth_plugin_shutdown.h" #include "sql/auth/auth_utility.h" #include "sql/auth/dynamic_privilege_table.h" #include "sql/auth/sql_authentication.h" // g_cached_authentication_plugins @@ -1973,12 +1974,17 @@ bool set_user_salt(ACL_USER *acl_user) { MYSQL_AUTHENTICATION_PLUGIN); if (plugin) { st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(plugin)->info; + Auth_plugin_operation_guard op_guard; - for (int i = 0; i < NUM_CREDENTIALS && !result; ++i) { - result = auth->set_salt(acl_user->credentials[i].m_auth_string.str, - acl_user->credentials[i].m_auth_string.length, - acl_user->credentials[i].m_salt, - &acl_user->credentials[i].m_salt_len); + if (!op_guard) { + result = true; + } else { + for (int i = 0; i < NUM_CREDENTIALS && !result; ++i) { + result = auth->set_salt(acl_user->credentials[i].m_auth_string.str, + acl_user->credentials[i].m_auth_string.length, + acl_user->credentials[i].m_salt, + &acl_user->credentials[i].m_salt_len); + } } plugin_unlock(nullptr, plugin); } diff --git a/sql/auth/sql_authentication.cc b/sql/auth/sql_authentication.cc index e19ccedff6e5..38d3e88de9a8 100644 --- a/sql/auth/sql_authentication.cc +++ b/sql/auth/sql_authentication.cc @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include /* std::string */ #include #include /* std::vector */ @@ -77,6 +79,7 @@ #include "sql/auth/auth_acls.h" #include "sql/auth/auth_common.h" #include "sql/auth/auth_internal.h" // optimize_plugin_compare_by_pointer +#include "sql/auth/auth_plugin_shutdown.h" #include "sql/auth/partial_revokes.h" #include "sql/auth/sql_auth_cache.h" // acl_cache #include "sql/auth/sql_security_ctx.h" @@ -1286,6 +1289,52 @@ int security_level(void) { external_roles_t g_external_roles; Cached_authentication_plugins *g_cached_authentication_plugins = nullptr; +namespace { + +class Auth_plugin_shutdown_state { + public: + bool begin_operation() { + std::lock_guard lock(m_mutex); + if (m_shutting_down) return false; + ++m_active_operations; + return true; + } + + void end_operation() { + std::lock_guard lock(m_mutex); + assert(m_active_operations > 0); + if (--m_active_operations == 0) m_cv.notify_all(); + } + + void start_shutdown_and_wait() { + std::unique_lock lock(m_mutex); + m_shutting_down = true; + m_cv.wait(lock, [&] { return m_active_operations == 0; }); + } + + private: + std::mutex m_mutex; + std::condition_variable m_cv; + size_t m_active_operations = 0; + bool m_shutting_down = false; +}; + +Auth_plugin_shutdown_state g_auth_plugin_shutdown_state; + +} // namespace + +bool begin_auth_plugin_operation() { + return g_auth_plugin_shutdown_state.begin_operation(); +} + +void end_auth_plugin_operation() { + g_auth_plugin_shutdown_state.end_operation(); +} + +void start_auth_plugin_shutdown_and_wait() { + g_auth_plugin_shutdown_state.start_shutdown_and_wait(); +} + bool disconnect_on_expired_password = true; extern bool initialized; @@ -3565,7 +3614,18 @@ static int do_auth_once(THD *thd, const LEX_CSTRING &auth_plugin_name, if (plugin) { st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(plugin)->info; - res = auth->authenticate_user(mpvio, &mpvio->auth_info); + Auth_plugin_operation_guard op_guard; + if (op_guard) { + DBUG_EXECUTE_IF("auth_plugin_before_callback_sync", { + const char act[] = "now SIGNAL auth_plugin_before_callback_entered"; + assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); + my_sleep(2000000); + };); + res = auth->authenticate_user(mpvio, &mpvio->auth_info); + } else { + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + res = CR_ERROR; + } if (unlock_plugin) plugin_unlock(thd, plugin); } else { @@ -3698,7 +3758,13 @@ static int do_multi_factor_auth(THD *thd, MPVIO_EXT *mpvio) { .auth_string_length; mpvio->status = MPVIO_EXT::START_MFA; st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(plugin)->info; - res = auth->authenticate_user(mpvio, &mpvio->auth_info); + Auth_plugin_operation_guard op_guard; + if (op_guard) { + res = auth->authenticate_user(mpvio, &mpvio->auth_info); + } else { + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + res = CR_ERROR; + } if (res == CR_OK_AUTH_IN_SANDBOX_MODE) { /* Server allows user account to connect in case registration is diff --git a/sql/auth/sql_mfa.cc b/sql/auth/sql_mfa.cc index 888280728b48..cc745d6e8a5d 100644 --- a/sql/auth/sql_mfa.cc +++ b/sql/auth/sql_mfa.cc @@ -27,6 +27,7 @@ #include "mysql/components/services/log_builtins.h" #include "mysql/plugin_auth.h" +#include "sql/auth/auth_plugin_shutdown.h" #include "sql/auth/authentication_policy.h" #include "sql/auth/sql_mfa.h" #include "sql/derror.h" /* ER_THD */ @@ -643,8 +644,10 @@ bool Multi_factor_auth_info::validate_plugins_in_auth_chain( inbuflen = gen_password.length(); set_generated_password(gen_password.c_str(), gen_password.length()); } - if (auth->generate_authentication_string(outbuf, &buflen, inbuf, - inbuflen)) { + Auth_plugin_operation_guard op_guard; + if (!op_guard || auth->generate_authentication_string(outbuf, &buflen, + inbuf, inbuflen)) { + if (!op_guard) my_error(ER_SERVER_SHUTDOWN, MYF(0)); plugin_unlock(nullptr, plugin); return (true); } @@ -894,8 +897,11 @@ bool Multi_factor_auth_info::init_registration(THD *thd, uint nth_factor) { /* convert auth string to base64 to be stored in mysql.user table */ char outbuf[MAX_FIELD_WIDTH] = {0}; unsigned int outbuflen = MAX_FIELD_WIDTH; - if (auth->generate_authentication_string( + Auth_plugin_operation_guard op_guard; + if (!op_guard || + auth->generate_authentication_string( outbuf, &outbuflen, reinterpret_cast(buf), buflen)) { + if (!op_guard) my_error(ER_SERVER_SHUTDOWN, MYF(0)); if (buf) delete[] buf; plugin_unlock(nullptr, plugin); return (true); @@ -982,9 +988,12 @@ bool Multi_factor_auth_info::finish_registration(THD *thd, LEX_USER *user_name, /* convert auth string to base64 to be stored in mysql.user table */ char outbuf[MAX_FIELD_WIDTH] = {0}; unsigned int outbuflen = MAX_FIELD_WIDTH; - if (auth->generate_authentication_string( + Auth_plugin_operation_guard op_guard; + if (!op_guard || + auth->generate_authentication_string( outbuf, &outbuflen, reinterpret_cast(challenge_response), challenge_response_len)) { + if (!op_guard) my_error(ER_SERVER_SHUTDOWN, MYF(0)); plugin_unlock(nullptr, plugin); return (true); } diff --git a/sql/auth/sql_user.cc b/sql/auth/sql_user.cc index af25999cfcb5..ce025f6ed370 100644 --- a/sql/auth/sql_user.cc +++ b/sql/auth/sql_user.cc @@ -102,6 +102,7 @@ #include "prealloced_array.h" #include "sql/auth/auth_internal.h" +#include "sql/auth/auth_plugin_shutdown.h" #include "sql/auth/sql_auth_cache.h" #include "sql/auth/sql_authentication.h" #include "sql/auth/sql_mfa.h" @@ -632,20 +633,27 @@ static bool auth_verify_password_history( */ if (cleartext_length && cleartext && 0 == (what_to_set & DIFFERENT_PLUGIN_ATTR) && - (auth->authentication_flags & AUTH_FLAG_USES_INTERNAL_STORAGE) && - auth->validate_authentication_string && - !auth->validate_authentication_string(cred_val.c_ptr_safe(), - (unsigned)cred_val.length()) && - auth->compare_password_with_hash && - !auth->compare_password_with_hash( - cred_val.c_ptr_safe(), (unsigned long)cred_val.length(), - cleartext, (unsigned long)cleartext_length, &is_error) && - !is_error) { - my_error(ER_CREDENTIALS_CONTRADICT_TO_HISTORY, MYF(0), user->length, - user->str, host->length, host->str); - /* password found in history */ - result = true; - goto end; + (auth->authentication_flags & AUTH_FLAG_USES_INTERNAL_STORAGE)) { + Auth_plugin_operation_guard op_guard; + if (!op_guard) { + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + result = true; + goto end; + } + if (auth->validate_authentication_string && + !auth->validate_authentication_string( + cred_val.c_ptr_safe(), (unsigned)cred_val.length()) && + auth->compare_password_with_hash && + !auth->compare_password_with_hash( + cred_val.c_ptr_safe(), (unsigned long)cred_val.length(), + cleartext, (unsigned long)cleartext_length, &is_error) && + !is_error) { + my_error(ER_CREDENTIALS_CONTRADICT_TO_HISTORY, MYF(0), user->length, + user->str, host->length, host->str); + /* password found in history */ + result = true; + goto end; + } } } @@ -893,16 +901,22 @@ static bool validate_password_require_current( current auth string. */ if ((auth->authentication_flags & AUTH_FLAG_USES_INTERNAL_STORAGE) && - auth->compare_password_with_hash && - auth->compare_password_with_hash( - acl_user->credentials[PRIMARY_CRED].m_auth_string.str, - (unsigned long)acl_user->credentials[PRIMARY_CRED] - .m_auth_string.length, - Str->current_auth.str, (unsigned long)Str->current_auth.length, - &is_error) && - !is_error) { - my_error(ER_INCORRECT_CURRENT_PASSWORD, MYF(0)); - return (true); + auth->compare_password_with_hash) { + Auth_plugin_operation_guard op_guard; + if (!op_guard) { + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + return (true); + } + if (auth->compare_password_with_hash( + acl_user->credentials[PRIMARY_CRED].m_auth_string.str, + (unsigned long)acl_user->credentials[PRIMARY_CRED] + .m_auth_string.length, + Str->current_auth.str, (unsigned long)Str->current_auth.length, + &is_error) && + !is_error) { + my_error(ER_INCORRECT_CURRENT_PASSWORD, MYF(0)); + return (true); + } } { @@ -1371,8 +1385,10 @@ bool set_and_validate_user_attributes( if (Str->first_factor_auth_info.uses_identified_by_clause) { inbuf = Str->first_factor_auth_info.auth.str; inbuflen = (unsigned)Str->first_factor_auth_info.auth.length; - if (auth->generate_authentication_string(outbuf, &buflen, inbuf, - inbuflen)) { + Auth_plugin_operation_guard op_guard; + if (!op_guard || auth->generate_authentication_string(outbuf, &buflen, + inbuf, inbuflen)) { + if (!op_guard) my_error(ER_SERVER_SHUTDOWN, MYF(0)); plugin_unlock(nullptr, plugin); what_to_set.m_what = NONE_ATTR; /* @@ -1390,10 +1406,15 @@ bool set_and_validate_user_attributes( Str->first_factor_auth_info.auth = {password, buflen}; } else if (Str->first_factor_auth_info.uses_authentication_string_clause) { assert(!is_role); - if (auth->validate_authentication_string( + Auth_plugin_operation_guard op_guard; + if (!op_guard || + auth->validate_authentication_string( const_cast(Str->first_factor_auth_info.auth.str), (unsigned)Str->first_factor_auth_info.auth.length)) { - my_error(ER_PASSWORD_FORMAT, MYF(0)); + if (!op_guard) + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + else + my_error(ER_PASSWORD_FORMAT, MYF(0)); plugin_unlock(nullptr, plugin); what_to_set.m_what = NONE_ATTR; return true; @@ -1749,13 +1770,16 @@ bool set_and_validate_user_attributes( std::string(Str->host.str), gen_password, 1}; generated_passwords.push_back(p); } - if (auth->generate_authentication_string(outbuf, &buflen, inbuf, + Auth_plugin_operation_guard op_guard; + if (!op_guard || + auth->generate_authentication_string(outbuf, &buflen, inbuf, inbuflen) || auth_verify_password_history(thd, &Str->user, &Str->host, Str->alter_status.password_history_length, Str->alter_status.password_reuse_interval, auth, inbuf, inbuflen, outbuf, buflen, history_table, what_to_set.m_what)) { + if (!op_guard) my_error(ER_SERVER_SHUTDOWN, MYF(0)); plugin_unlock(nullptr, plugin); what_to_set.m_what = NONE_ATTR; /* @@ -1817,10 +1841,15 @@ bool set_and_validate_user_attributes( interdependencies if mysql_create_user() is refactored. */ assert(!is_role); - if (auth->validate_authentication_string( + Auth_plugin_operation_guard op_guard; + if (!op_guard || + auth->validate_authentication_string( const_cast(Str->first_factor_auth_info.auth.str), (unsigned)Str->first_factor_auth_info.auth.length)) { - my_error(ER_PASSWORD_FORMAT, MYF(0)); + if (!op_guard) + my_error(ER_SERVER_SHUTDOWN, MYF(0)); + else + my_error(ER_PASSWORD_FORMAT, MYF(0)); plugin_unlock(nullptr, plugin); what_to_set.m_what = NONE_ATTR; return (true); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index d5fe903e91b7..3b9b731a11b7 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -71,6 +71,7 @@ #include "prealloced_array.h" #include "sql/auth/auth_acls.h" #include "sql/auth/auth_common.h" // check_table_access +#include "sql/auth/auth_plugin_shutdown.h" #include "sql/auto_thd.h" // Auto_THD #include "sql/current_thd.h" #include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_client @@ -2054,6 +2055,10 @@ void plugin_shutdown() { if (initialized) { size_t count = plugin_array->size(); + + // Stop new auth plugin operations and drain in-flight callbacks first. + start_auth_plugin_shutdown_and_wait(); + mysql_mutex_lock(&LOCK_plugin); reap_needed = true;