ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Node.js에서 MySQL 연동 실패 해결 (MySQL 8)
    Knowledge 2021. 1. 14. 19:56

     

     

    너무나 잘 돌아가던 Node.js 서버 코드를 다시 돌리던 중에 황당하게도 아예 연결이 되지 않는 현상이 나타났다. 당황해서 로그를 확인하니 다음과 같은 에러가 나고 있었다.

     

    Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client 

     

    마지막으로 코드가 돌던 때와 약간 시차가 있기는 했지만 사실 근 1년이 넘도록 AWS에서 잘 돌아가고 있던 코드였기에 코드 자체의 에러보다는 그 사이에 뭔가 설정이 바뀌었을 가능성이 더 높았다. 한참을 찾았는데 역시나 예상대로였다. 문제의 원인과 해결책에 대해 남겨본다.

     

     

    원인

     

    MySQL 8부터 기본 인증 프로토콜이 caching_sha2_password로 변경되었다. 그 전까지는 mysql_native_password가 사용되고 있었다. 변경의 효과는 기존 플레인 텍스트로 전달되던 패스워드를 sha256 해시를 적용해서 전달하는 점 그리고 퍼포먼스를 위해 패스워드를 미리 캐시해두는 점이다. 문제는 이 변경이 default 옵션으로 적용이 되어버렸다는 것이다. 무려 20년 넘게 사용되던 기존 default 인증 방식을 그냥 바꿔버렸다. (출처)

     

    사실 이 변경이 다른 곳에 크게 영향을 주지 않고 관련된 연결 라이브러리들에 잘 구현이 되어 지원되었다면 큰 문제가 없었을 것이다. 하지만 세상이 그리 만만한게 아니어서 수 많은 사용자를 거느린 mysqljs에 이 변경이 지원되지 않았고, 그게 문제가 되었던 것이다. mysql_native_password 방식으로 MySQL에 쿼리를 날리려던 mysqljs는 당연히 연결에 실패할 수밖에 없었던 것이다.

     

     

    해결책

     

    근본적인 해결책은 caching_sha2_password를 지원하는 클라이언트 라이브러리를 사용하거나 만들어 쓰는 것이다. 아마도 이것이 MySQL이 이 변경을 하면서 기대했던 방법일 것이다. 그러나 라이브러리를 찾고 기존 구현을 바꿔야 하니 귀찮기만 할 따름이었다.

     

    다른 해결책은 MySQL의 설정을 변경하여 mysql_native_password를 접속 프로토콜로 변경하는 것이다. (또는 다운그레이드를 하는 것도 방법이다.) 그러나 아무리 귀찮대도 평문을 날리는 기존 구현으로 롤백을 하는데 대해 약간 찔리는 구석이 없지 않아 애매했다.

     

    결국 선택한 해결책은 내가 접속할 계정에 대해서만 예외를 적용하는 방식이었다. MySQL 콘솔에 들어가 다음과 같은 명령으로 이를 적용할 수 있다.

     

    ALTER USER 'USER'@'localhost' IDENTIFIED WITH mysql_native_password BY 'PASSWORD'

     

    USER에 MySQL 계정을 넣어주고, PASSWORD에 사용하던 MySQL 암호를 넣으면 된다. 그리고 @'localhost' 부분은 로컬호스트에서 접속할 때만 허용을 하는 것을 뜻한다. 만약 리모트 접속에서도 쓰고 싶다면 이 부분을 빼면 된다.

     

    종합하면 다음과 같은 적용 예를 생각할 수 있다.

     

    // 계정: msacct, 암호: 1004, 로컬 접속만 적용
    ALTER USER 'msacct'@'localhost' IDENTIFIED WITH mysql_native_password BY '1004'
    
    // 계정: root, 암호: 1234, 로컬 접속만 적용
    ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '1234'
    
    // 계정: root, 암호: 1111, 모든 접속에 적용 (막장이지만 개발섭에 실제 사용 중...)
    ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY '1111'

     

     

    Fin.

    반응형

    댓글

Calvin's Memo