MySQL 8.0.30
Source Code Documentation
Expired Password

Since MySQL 5.6.7, a MySQL account can be expired.

If a account is expired, the session is in a restricted mode which only permits SET PASSWORD = .. and similar SET commands. Other statements will fail with an error like this:

ERROR 1820 (HY000): You must SET PASSWORD before executing this statement
@ ERROR
Definition: binlog.cc:4165
static MYSQL mysql
Definition: mysql.cc:153
const std::string SELECT("SELECT")
Name of the static privileges.
@ PASSWORD
Definition: sql_yacc.h:448
Definition: mysqlslap.cc:213

Not all clients can properly deal with that error. So on the protocol side exists a safeguard CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS capability flag exists to prevent clients from entering this "sandbox" mode. Only clients that can handle this sandbox mode should report CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS on. Usually this means all interactive clients and all applications that got adjusted to handle the relevant SQL error.

If a client is not setting that capability and it tries to login with an account that has an expired password, the server will return an ERR_Packet for the Connection Phase or the COM_CHANGE_USER request.

The idea is to block any activity until the password is reset.

See also
MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, mysql_options, ACL_USER::password_expired, ACL_USER::password_lifetime, acl_authenticate