MySQL 8.0으로 업그레이드하거나 서버를 변경한 후 PHP에서 데이터베이스 연결을 시도하면 갑자기 'Client does not support authentication protocol' 에러가 떨어진다. 다만 정확히 뭐가 문제인지, 왜 갑자기 안 되는지 모르는 개발자가 대부분이다. 이번에는 MySQL 8.0의 기본 인증 방식 변화가 뭔지, 왜 이 에러가 나는지, 그리고 어떻게 해결하는지 정확하게 정리해서 소개하겠다.
MySQL 5.7까지는 비밀번호 인증에 'mysql_native_password' 플러그인을 사용했다. 이건 상대적으로 오래된 인증 방식이지만 대부분의 드라이버가 지원했다. 그런데 MySQL 8.0부터는 보안을 강화하려고 'caching_sha2_password'를 기본 인증 프로토콜로 변경했다. 문제는 구형 PHP 드라이버나 PDO, MySQLi 라이브러리가 이 새로운 방식을 지원하지 않는다는 것이다. 특히 PHP 5.x나 초기 PHP 7.x 버전에서 자주 만난다.
인증 프로토콜이란 클라이언트와 서버가 비밀번호를 주고받을 때 사용하는 암호화 방식이다. 서버가 'caching_sha2_password'를 요구하는데 클라이언트가 이를 이해하지 못하면 연결이 실패하는 것이다.
가장 빠르고 간단한 해결책은 MySQL 사용자 계정의 인증 방식을 기존 방식으로 되돌리는 것이다. MySQL 서버에 root나 관리자 권한으로 접속한 후 다음 SQL을 실행하면 된다.
ALTER USER 'your_username'@'your_host' IDENTIFIED WITH mysql_native_password BY 'your_password';
'your_username'은 실제 데이터베이스 사용자 이름, 'your_host'는 접속 출처(보통 localhost 또는 %), 'your_password'는 비밀번호로 바꾸면 된다. 예를 들어 로컬호스트의 'appuser' 계정이라면:
ALTER USER 'appuser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'appuser123';
실행 후 권한을 새로고침한다.
FLUSH PRIVILEGES;
이제 PHP에서 같은 비밀번호로 연결하면 된다. caching_sha2_password는 건너뛰고 mysql_native_password로 인증하기 때문에 대부분의 PHP 버전에서 작동한다.
PHP 7.4 이상과 최신 MySQLi 드라이버는 caching_sha2_password를 기본적으로 지원한다. 따라서 PHP를 업그레이드하면 아무것도 변경하지 않아도 MySQL 8.0 인증이 작동한다.
하지만 점유율이 높은 공유 호스팅 환경에서는 PHP 버전 업그레이드가 쉽지 않을 수 있다. 그럴 땐 방법 1이 더 현실적이다.
MySQL 8.0은 RSA 공개 키 기반 인증도 지원한다. PHP PDO 연결 시 다음 옵션을 추가할 수 있다.
$pdo = new PDO(
'mysql:host=localhost;dbname=your_db',
'your_username',
'your_password',
array(
PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
)
);
다만 이 방법은 SSL 인증서 설정이 필요하고 복잡하기 때문에 실무에서는 방법 1을 훨씬 많이 쓴다.
✗ 잘못된 방법: 인증 플러그인을 확인하지 않고 그냥 연결 시도
try {
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'password');
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
// 결과: Client does not support authentication protocol requested by server
}
✓ 올바른 방법: MySQL 사용자 계정을 먼저 mysql_native_password로 변경한 후 연결
// 데이터베이스에서 먼저 실행:
// ALTER USER 'user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
// FLUSH PRIVILEGES;
try {
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'password');
echo 'Connection successful';
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
✗ 잘못된 방법: caching_sha2_password 인증을 클라이언트가 이해하지 못하는 상태
$mysqli = new mysqli('localhost', 'user', 'password', 'mydb');
if ($mysqli->connect_error) {
echo 'Connect Error: ' . $mysqli->connect_error;
// 결과: Client does not support authentication protocol requested by server
}
$mysqli->close();
✓ 올바른 방법: MySQLi에서도 동일하게 먼저 계정을 mysql_native_password로 변경
// MySQL 서버에서 미리 실행:
// ALTER USER 'user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
// FLUSH PRIVILEGES;
$mysqli = new mysqli('localhost', 'user', 'password', 'mydb');
if ($mysqli->connect_error) {
echo 'Connect Error: ' . $mysqli->connect_error;
} else {
echo 'Connection successful';
}
$mysqli->close();
✗ 실수 1: 인증 프로토콜을 변경했는데 권한을 새로고침하지 않음
ALTER USER 명령 후에는 반드시 FLUSH PRIVILEGES를 실행해야 한다. 그렇지 않으면 변경 사항이 적용되지 않는다.
✗ 실수 2: 모든 사용자를 한 번에 변경하려고 시도
root나 다른 관리 계정도 caching_sha2_password를 사용할 수 있다. 필요한 계정만 명시적으로 변경하는 것이 안전하다. 와일드카드(%)를 쓸 때는 특히 주의해야 한다.
// 모든 호스트에서 접속하는 사용자라면
ALTER USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
✗ 실수 3: 로컬호스트와 원격 접속의 호스트 이름을 구분하지 않음
MySQL에서는 'user'@'localhost'와 'user'@'127.0.0.1', 'user'@'remote.host'를 모두 다른 계정으로 취급한다. 각각 따로 변경해야 한다.
변경 전에 현재 상태를 확인할 수 있다. MySQL 관리자 권한으로 다음 쿼리를 실행하면:
SELECT user, host, plugin FROM mysql.user WHERE user='your_username';
plugin 열에 'caching_sha2_password'가 표시되면 MySQL 8.0 기본 인증이고, 'mysql_native_password'가 표시되면 이미 호환 모드로 설정된 것이다.
MySQL 8.0부터의 caching_sha2_password 인증 프로토콜은 보안 강화를 위한 변화지만, 구형 PHP 드라이버와의 호환성 문제를 일으킨다. 대부분의 실무 환경에서는 사용자 계정의 인증 플러그인을 mysql_native_password로 되돌리는 것이 가장 빠르고 안전한 해결책이다. ALTER USER 한 줄과 FLUSH PRIVILEGES 명령으로 문제를 완전히 해결할 수 있다는 점을 잊지 말자. 이 글의 '방법 1' 섹션을 참고해 데이터베이스 계정을 변경한 후, PHP 연결 코드를 다시 실행하면 ERROR 1251은 더 이상 나타나지 않을 것이다.