"계정이 잠겼다"는 증상은 원인이 둘로 갈린다. 하나는 계정 자체가 ACCOUNT LOCK 상태인 것이고, 다른 하나는 비밀번호를 잊어 로그인하지 못하는 것이다. 이 둘은 해결 방법이 전혀 다르므로 먼저 어느 쪽인지 가른다.
관리자 계정으로 접속할 수 있다면 잠금 상태를 확인하고 바로 푼다.
SELECT user, host, account_locked FROM mysql.user WHERE user = 'appuser';
ALTER USER 'appuser'@'%' ACCOUNT UNLOCK;
ACCOUNT LOCK / ACCOUNT UNLOCK 는 MySQL 5.7.6 이상과 MariaDB 10.4 이상에서 쓸 수 있다. 오류 메시지는 ERROR 3118 (HY000): Access denied for user ... Account is locked 형태다.
MySQL 8.0.19 이상은 로그인 실패 횟수에 따라 계정을 일시 잠그는 정책도 지원한다.
ALTER USER 'appuser'@'%' FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 1;
MariaDB 에는 이 두 옵션이 없다. 대신 max_connect_errors 에 걸려 호스트가 차단되는 경우가 있고, 이때는 FLUSH HOSTS 로 푼다.
관리자 계정으로 접속이 되면 한 줄이면 끝난다.
ALTER USER 'appuser'@'%' IDENTIFIED BY '${PASSWORD}';
root 비밀번호까지 잃어 접속 자체가 안 되면 권한 검사를 건너뛰고 기동해야 한다. 이때 반드시 네트워크를 함께 막는다. --skip-grant-tables 만 주고 올리면 그 순간 누구나 인증 없이 붙을 수 있다.
# 1. 서비스 중지
systemctl stop mariadb
# 2. 권한 검사를 끄되 네트워크는 닫고 기동한다
systemctl set-environment MYSQLD_OPTS="--skip-grant-tables --skip-networking"
systemctl start mariadb
# 3. 로컬 소켓으로 접속
mysql -u root
--skip-grant-tables 상태에서는 ALTER USER 가 동작하지 않는다. 권한 테이블을 메모리로 다시 읽어들인 뒤에 바꾼다.
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY '${PASSWORD}';
끝나면 옵션을 걷어내고 정상 기동한다.
systemctl stop mariadb
systemctl unset-environment MYSQLD_OPTS
systemctl start mariadb
UPDATE mysql.user SET password = ... 로 직접 고치는 옛 방법은 MySQL 5.7 이후 컬럼 이름이 authentication_string 으로 바뀌어 그대로는 통하지 않는다. ALTER USER 를 쓴다.
MariaDB 는 기본적으로 root@localhost 에 unix_socket 플러그인을 물려 두므로, OS 의 root 로 mysql 을 실행하면 비밀번호 없이 들어간다. 비밀번호 인증으로 바꾸려면 ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('${PASSWORD}') 형태를 쓴다.