우분투 MySQL 설치 후 root 접속 안 됨: ERROR 1045 Access denied와 auth_socket, 원격 접속 설정

이 글의 핵심

우분투에서 apt로 MySQL을 설치하면 root 계정은 비밀번호가 아니라 리눅스 사용자 이름으로 인증하는 auth_socket 방식으로 만들어집니다. 그래서 sudo mysql은 되는데 mysql -u root -p는 ERROR 1045로 막힙니다. 이 글은 이 동작의 이유와 확인 방법, mysql_secure_installation이 SET PASSWORD 오류로 무한 반복되는 문제의 해결, root 대신 앱 전용 계정을 만드는 방법, 원격 접속에 필요한 bind-address·계정 호스트·방화벽 설정, 그리고 ERROR 2002 소켓 오류의 원인을 차례로 설명합니다.

설치는 끝났는데 root로 들어가지지 않는다

우분투에서 MySQL 설치는 명령 한 줄이면 끝납니다. 문제는 그 다음입니다. 다른 OS나 예전 튜토리얼에서 하던 대로 root로 접속하면 바로 막힙니다.

mysql -u root -p
Enter password:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

설치 중에 비밀번호를 정한 적이 없으니 그냥 Enter를 눌러 보면 메시지 끝만 (using password: NO)로 바뀔 뿐 결과는 같습니다. 그런데 sudo를 붙이면 비밀번호도 묻지 않고 들어가집니다.

sudo mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
...
mysql>

이건 설치가 잘못된 것이 아니라 우분투 MySQL 패키지의 의도된 기본 설정입니다. 이 동작을 이해하지 못한 채 “root 비밀번호 초기화” 같은 방법을 따라 하면, 서버를 --skip-grant-tables로 띄우는 등 필요 이상으로 위험한 작업을 하게 됩니다. 이 글에서는 왜 이렇게 동작하는지부터 설명하고, 그 위에서 실제로 필요한 계정과 접속 설정을 만드는 순서로 진행합니다.

기준 환경: Ubuntu 22.04 LTS 또는 24.04 LTS, 우분투 공식 저장소의 mysql-server 패키지(두 버전 모두 MySQL 8.0 계열). Oracle의 MySQL APT 저장소에서 설치했거나 MariaDB를 설치했다면 기본 인증 방식이 다를 수 있습니다.

apt로 MySQL 8.0 설치하고 상태 확인하기

설치 자체는 간단합니다.

sudo apt update
sudo apt install mysql-server

설치가 끝나면 서비스가 자동으로 시작되고, 부팅 시 자동 시작도 등록됩니다. 실제로 떠 있는지 확인합니다.

systemctl status mysql
mysql --version

Active: active (running)이 보이면 정상입니다. 버전은 mysql Ver 8.0.xx-0ubuntu... 형태로 나오며, 뒤의 0ubuntu는 우분투가 패키징한 버전이라는 뜻입니다.

설치 과정에서 root 비밀번호를 묻지 않았다는 점이 중요합니다. 예전 우분투 버전이나 다른 배포 방식에서는 설치 중 비밀번호 입력 화면이 떴지만, 현재 우분투 패키지는 비밀번호 없이 root를 만들고 소켓 인증으로 보호합니다. 그 이유가 다음 절입니다.

왜 sudo mysql은 되고 mysql -u root -p는 안 되는가

root@localhost는 auth_socket으로 인증한다

MySQL 계정마다 어떤 방식으로 인증할지를 정하는 “인증 플러그인”이 붙어 있습니다. sudo mysql로 들어가서 확인해 보면 이렇습니다.

SELECT user, host, plugin FROM mysql.user;
+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| debian-sys-maint | localhost | caching_sha2_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session    | localhost | caching_sha2_password |
| mysql.sys        | localhost | caching_sha2_password |
| root             | localhost | auth_socket           |
+------------------+-----------+-----------------------+

root의 플러그인이 auth_socket입니다. 이 플러그인은 비밀번호를 전혀 보지 않습니다. 대신 클라이언트가 유닉스 소켓 파일(/var/run/mysqld/mysqld.sock)로 접속했을 때, 운영체제에 “이 소켓 반대편 프로세스를 실행한 리눅스 사용자가 누구냐”를 물어보고, 그 이름이 MySQL 계정 이름과 같으면 통과시킵니다.

  • sudo mysql: 클라이언트가 리눅스 root 권한으로 실행되므로, 리눅스 사용자 root = MySQL 사용자 root. 통과합니다.
  • mysql -u root -p(일반 사용자로 실행): 리눅스 사용자는 예를 들어 ubuntu인데 MySQL 사용자로 root를 요청했으니 이름이 다릅니다. 비밀번호를 무엇으로 입력하든 거부됩니다.

이렇게 설정하는 이유는 보안입니다. 비밀번호가 없으니 약한 비밀번호가 설정되거나 유출될 일이 없고, MySQL root 권한은 서버의 sudo 권한을 가진 사람에게만 주어집니다. 네트워크(TCP)로는 root 인증 자체가 불가능하므로, 원격에서 root 비밀번호를 무작위로 대입하는 공격도 의미가 없습니다.

참고로 목록의 debian-sys-maint는 우분투·데비안 패키지가 업그레이드나 유지 보수 작업에 쓰는 계정입니다. 비밀번호는 /etc/mysql/debian.cnf에 저장되어 있으며, 직접 사용하거나 지우지 않는 것이 좋습니다. 위 표의 플러그인 이름은 MySQL 8.0의 기본값 기준이며, 버전이나 설치 이력에 따라 일부 계정이 mysql_native_password로 표시될 수도 있습니다.

root에 비밀번호를 붙여야 할까

root에 비밀번호 인증을 붙이는 방법도 있습니다. 하지만 대부분의 경우 root는 그대로 두고, 앱이나 사람이 쓸 계정을 따로 만드는 편이 낫습니다. 서버 관리 작업은 sudo mysql로 충분하고, 애플리케이션이 root로 DB에 접속하는 구성은 SQL 인젝션 같은 사고가 났을 때 피해 범위를 서버 전체로 넓힙니다. 계정 생성 방법은 뒤의 “root 대신 앱 전용 계정 만들기”에서 설명합니다.

그래도 root에 비밀번호가 꼭 필요하다면(예: 오래된 관리 도구가 root 비밀번호 접속만 지원하는 경우) 이렇게 바꿉니다.

ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '강력한-비밀번호';

이후에는 mysql -u root -p로 비밀번호 접속이 되는 대신, sudo mysql은 더 이상 비밀번호 없이 들어가지지 않습니다. 원래대로 되돌리려면 비밀번호로 접속해서 다음을 실행합니다.

ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;

인터넷의 예전 글에는 IDENTIFIED WITH mysql_native_password를 쓰라는 내용이 많습니다. mysql_native_password는 MySQL 8.0에서 사용 중단(deprecated)으로 표시되었고, 8.4 LTS에서는 기본으로 비활성화되어 서버 옵션(mysql_native_password=ON)을 켜야 쓸 수 있으며, 9.0에서는 플러그인 자체가 제거되었습니다. 나중에 8.4나 9.x로 올리면 이 방식으로 만든 계정은 로그인할 수 없게 되므로, 8.0의 기본값인 caching_sha2_password를 쓰는 편이 좋습니다.

mysql_secure_installation이 SET PASSWORD 오류로 무한 반복될 때

설치 후 sudo mysql_secure_installation을 실행하는 것이 일반적인 권장 절차입니다. 익명 사용자 삭제, root 원격 로그인 금지, test 데이터베이스 삭제를 한 번에 해 주는 스크립트입니다. 그런데 우분투에서 root 비밀번호를 설정하겠다고 답하면 이런 오류가 나고, 같은 질문이 끝없이 반복되는 경우가 있습니다.

 ... Failed! Error: SET PASSWORD has no significance for user 'root'@'localhost' as the authentication method used doesn't store authentication data in the MySQL server. Please consider using ALTER USER instead if you want to change authentication parameters.

New password:

원인은 앞 절의 내용 그대로입니다. 스크립트는 SET PASSWORD로 root 비밀번호를 바꾸려 하는데, root가 auth_socket이라 저장할 비밀번호 자체가 없으니 MySQL이 거부합니다. 스크립트는 실패를 처리하지 못하고 다시 비밀번호를 묻습니다. 이 동작은 우분투 22.04 시기의 MySQL 8.0 업데이트 이후 많이 보고되었고, 패키지 버전에 따라 증상이 나타나지 않거나 비밀번호 설정 단계가 건너뛰어지는 경우도 있습니다.

해결 방법은 두 가지입니다.

방법 1: 비밀번호 설정 단계만 건너뛴다. 이 오류가 반복되면 Ctrl+C로 스크립트를 끝내고 다시 실행한 뒤, root 비밀번호를 바꾸겠느냐는 질문에 n(또는 Enter가 아닌 다른 키)으로 답합니다. root를 auth_socket으로 유지할 생각이라면 이것으로 충분합니다. 나머지 질문(익명 사용자 삭제, 원격 root 로그인 금지, test DB 삭제, 권한 테이블 다시 로드)에는 모두 y로 답하면 됩니다.

방법 2: 잠시 비밀번호 인증으로 바꿨다가 되돌린다. 스크립트를 처음부터 끝까지 정상 흐름으로 실행하고 싶다면, 먼저 root에 임시 비밀번호를 붙입니다.

sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '임시-비밀번호';
EXIT;
sudo mysql_secure_installation   # 이제 임시 비밀번호로 진행

스크립트가 끝나면 root를 다시 소켓 인증으로 되돌립니다. 이 단계를 잊으면 sudo mysql이 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)로 막히는데, 이건 비밀번호가 생겼기 때문이고 mysql -u root -p로 들어가면 됩니다.

mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;
EXIT;

스크립트 첫 질문인 VALIDATE PASSWORD 컴포넌트를 켜면, 이후 만드는 모든 계정의 비밀번호가 정책을 만족해야 합니다. 정책보다 약한 비밀번호로 계정을 만들려고 하면 이렇게 거부됩니다.

ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

정책을 켜는 것 자체는 좋은 선택입니다. 이 오류가 나면 정책 수준을 낮추기보다 대소문자·숫자·특수문자가 섞인 충분히 긴 비밀번호를 쓰는 것이 맞습니다. 현재 정책은 SHOW VARIABLES LIKE 'validate_password%';로 확인할 수 있습니다.

root 대신 앱 전용 계정 만들기

애플리케이션, 개발용 GUI 도구, 다른 팀원이 쓸 계정은 root와 분리해 만듭니다. 데이터베이스를 하나 만들고 그 DB에만 권한을 주는 것이 기본 형태입니다.

sudo mysql
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

CREATE USER 'appuser'@'localhost' IDENTIFIED BY '강력한-비밀번호';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';

MySQL 8.0에서는 utf8mb4가 기본 문자셋이지만, 명시해 두면 설정 파일이나 버전이 달라져도 한글과 이모지가 깨질 걱정이 없습니다. CREATE USER와 GRANT로 만든 계정은 바로 적용되므로 FLUSH PRIVILEGES는 필요 없습니다. 그 명령은 mysql.user 테이블을 직접 UPDATE했을 때나 필요한데, 그런 방식은 권장되지 않습니다.

이제 sudo 없이 비밀번호로 접속됩니다.

mysql -u appuser -p appdb

권한은 필요한 만큼만 주는 편이 좋습니다. 위의 ALL PRIVILEGES ON appdb.*는 그 DB 안에서는 테이블 생성·삭제까지 모두 허용합니다. 운영 환경에서 마이그레이션 도구와 실제 애플리케이션을 분리할 수 있다면, 애플리케이션 계정에는 SELECT, INSERT, UPDATE, DELETE만 주는 구성도 고려할 만합니다.

CREATE USER 'appweb'@'localhost' IDENTIFIED BY '또-다른-강력한-비밀번호';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appweb'@'localhost';
SHOW GRANTS FOR 'appuser'@'localhost';

클라이언트가 caching_sha2_password를 모를 때

MySQL 8.0의 기본 인증 플러그인 caching_sha2_password를 지원하지 않는 오래된 드라이버나 도구로 접속하면 이런 오류가 납니다.

Authentication plugin 'caching_sha2_password' cannot be loaded

먼저 드라이버나 도구를 최신 버전으로 업데이트하는 것이 정석입니다. 최근 몇 년 사이의 주요 언어 드라이버와 GUI 도구는 대부분 이 플러그인을 지원합니다. 도저히 업데이트할 수 없는 레거시 시스템이라면 해당 계정만 IDENTIFIED WITH mysql_native_password BY '...'로 바꾸는 방법이 있지만, 앞에서 말한 대로 이 플러그인은 8.4에서 기본 비활성화, 9.0에서 제거되었으므로 8.0에서만 통하는 임시 방편입니다.

Java(JDBC)에서는 Public Key Retrieval is not allowed 오류가 자주 보입니다. caching_sha2_password는 TLS가 아닌 연결에서 첫 인증 시 서버의 RSA 공개키로 비밀번호를 암호화해 보내는데, 드라이버가 기본적으로 그 공개키 요청을 막기 때문입니다. TLS 연결을 쓰거나, 신뢰할 수 있는 네트워크라면 연결 문자열에 allowPublicKeyRetrieval=true를 추가하는 것으로 해결합니다.

다른 PC에서 접속하려면: bind-address, 계정 호스트, 방화벽

다른 서버나 개발 PC에서 이 MySQL에 접속하려면 세 가지가 모두 맞아야 합니다. 하나라도 빠지면 각기 다른 오류가 나므로, 오류 메시지로 어디가 막혔는지 구분할 수 있습니다.

1단계: MySQL이 외부 인터페이스에서 듣게 하기

우분투 패키지의 기본 설정은 로컬에서만 접속을 받습니다. /etc/mysql/mysql.conf.d/mysqld.cnf에 이런 줄이 있습니다.

bind-address            = 127.0.0.1
mysqlx-bind-address     = 127.0.0.1

127.0.0.1은 자기 자신에서 오는 연결만 받는다는 뜻입니다. 이 상태로 다른 PC에서 접속하면 연결 자체가 거부됩니다.

ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.0.20:3306' (111)

끝의 (111)은 리눅스의 “Connection refused”로, 서버까지는 도달했지만 그 포트에서 듣는 프로세스가 없다는 뜻입니다. 설정을 바꿉니다.

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address            = 0.0.0.0        # 모든 IPv4 인터페이스
# 또는 서버의 특정 내부 IP만: bind-address = 192.168.0.20

0.0.0.0은 모든 네트워크 인터페이스에서 받는다는 뜻이라, 서버가 공인 IP를 직접 가지고 있다면 인터넷 전체에 3306 포트가 열릴 수 있습니다. 내부망 IP가 따로 있다면 그 IP만 지정하는 편이 안전합니다. X 프로토콜(33060 포트)을 쓰지 않는다면 mysqlx-bind-address는 그대로 두면 됩니다.

sudo systemctl restart mysql
sudo ss -tlnp | grep 3306

ss 출력에서 127.0.0.1:3306이 아니라 0.0.0.0:3306(또는 지정한 IP)으로 바뀌었는지 확인합니다.

2단계: 원격 호스트용 계정 만들기

MySQL 계정은 '사용자'@'호스트' 쌍으로 식별됩니다. 앞에서 만든 'appuser'@'localhost'는 이름만 같을 뿐, 다른 PC에서 오는 연결에는 해당하지 않습니다. 계정이 없으면 이런 오류가 납니다.

ERROR 1130 (HY000): Host '192.168.0.15' is not allowed to connect to this MySQL server

접속할 곳에 맞는 호스트로 계정을 만듭니다.

-- 특정 내부망 대역에서만
CREATE USER 'appuser'@'192.168.0.%' IDENTIFIED BY '강력한-비밀번호';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'192.168.0.%';

-- 어디서든 (꼭 필요할 때만, 방화벽과 함께)
CREATE USER 'appuser'@'%' IDENTIFIED BY '강력한-비밀번호';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'%';

'%'는 모든 호스트를 뜻합니다. 편하지만, 3306이 인터넷에 열려 있다면 전 세계에서 이 계정으로 비밀번호 대입을 시도할 수 있게 됩니다. 접속할 IP나 대역을 알고 있다면 그 범위로 좁히세요. 또 하나 알아 둘 점은 '%' 계정이 있어도 서버 자신에서 localhost로 소켓 접속할 때는 'appuser'@'localhost' 계정이 따로 필요하다는 것입니다. MySQL에서 localhost는 소켓 연결을 뜻하는 특별한 호스트 이름이라, 로컬 접속과 원격 접속이 모두 필요하면 두 계정을 같은 비밀번호로 각각 만드는 것이 일반적입니다.

root는 원격 계정을 만들지 않는 것이 원칙입니다. mysql_secure_installation의 “Disallow root login remotely” 질문이 바로 이것을 막는 설정입니다.

3단계: 방화벽 열기

서버에서 ufw를 쓰고 있다면 3306 포트를 열어야 합니다. 열 때도 출발지를 지정하는 것이 좋습니다.

sudo ufw status
sudo ufw allow from 192.168.0.0/24 to any port 3306 proto tcp

ufw allow 3306처럼 출발지 없이 열면 모든 곳에 열립니다. AWS, GCP, 오라클 클라우드 같은 클라우드 서버라면 OS의 ufw와 별개로 콘솔의 보안 그룹(방화벽 규칙)에도 인바운드 3306을 추가해야 합니다. 방화벽에서 막히면 연결 거부가 아니라 응답이 없다가 시간 초과로 끝나는 경우가 많습니다.

ERROR 2003 (HY000): Can't connect to MySQL server on '203.0.113.10:3306' (110)

(110)은 “Connection timed out”입니다. (111)이면 bind-address를, (110)이면 방화벽과 보안 그룹을, ERROR 1130이면 계정의 호스트를, ERROR 1045이면 비밀번호나 계정 이름을 의심하면 됩니다.

원격 접속이 개발이나 관리 목적이라면, 3306을 열지 않고 SSH 터널을 쓰는 방법이 더 안전합니다. 서버는 127.0.0.1에서만 듣게 두고, 내 PC에서 터널을 만듭니다.

ssh -L 3307:127.0.0.1:3306 사용자@서버주소
# 다른 터미널에서
mysql -h 127.0.0.1 -P 3307 -u appuser -p

이 경우 MySQL 입장에서는 연결이 서버 자신의 127.0.0.1에서 오므로 계정은 'appuser'@'localhost'가 아니라 'appuser'@'127.0.0.1'로 매칭될 수 있습니다. MySQL은 localhost라는 계정 호스트를 TCP 루프백 연결에도 매칭하는 경우가 많지만, 접속이 거부되면 'appuser'@'127.0.0.1' 계정을 추가해 보세요.

ERROR 2002: 소켓으로 연결할 수 없을 때

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

이 오류는 인증 이전 단계에서 실패한 것입니다. 클라이언트가 소켓 파일을 찾아갔는데 파일이 없다는 뜻이고, 거의 항상 MySQL 서버가 실행 중이 아니라는 의미입니다. 끝의 (2)는 “No such file or directory”입니다.

먼저 서버 상태와 로그를 봅니다.

systemctl status mysql
sudo journalctl -u mysql -n 50 --no-pager
sudo tail -n 50 /var/log/mysql/error.log

서버가 시작에 실패하는 흔한 원인은 다음과 같습니다.

  • 설정 파일 오류: mysqld.cnf를 수정하다 오타를 내거나, 존재하지 않는 옵션을 넣으면 시작하지 못합니다. 에러 로그에 unknown variable 같은 메시지와 함께 문제의 줄이 나옵니다. 방금 바꾼 설정을 되돌리고 다시 시작해 봅니다.
  • 디스크 부족: /var/lib/mysql이 있는 파티션이 꽉 차면 시작하지 못하거나 시작 직후 멈춥니다. df -h로 확인합니다.
  • 메모리 부족: 메모리가 아주 작은 VPS에서는 시작 중 OOM으로 종료되기도 합니다. journalctl이나 dmesg에 Out of memory가 보이면 스왑을 추가하거나 버퍼 설정을 줄여야 합니다.
  • 포트 충돌: 다른 MySQL이나 MariaDB, 또는 Docker 컨테이너가 이미 3306을 쓰고 있으면 Address already in use로 실패합니다. sudo ss -tlnp | grep 3306으로 누가 쓰는지 확인합니다.

원인을 고친 뒤 서버를 다시 시작하고 상태를 확인합니다.

sudo systemctl start mysql

WSL2의 우분투에서 이 오류가 난다면, systemd가 꺼진 상태라 부팅 후 서비스가 자동으로 시작되지 않은 경우가 많습니다. 최근 WSL의 우분투는 systemd가 기본으로 켜져 있지만, 오래전에 만든 배포판이라면 /etc/wsl.conf에 [boot] 아래 systemd=true를 넣고 wsl --shutdown 후 다시 열거나, 그때마다 sudo service mysql start로 시작해야 합니다.

(13)으로 끝나는 경우는 “Permission denied”로, 소켓 디렉터리의 권한 문제입니다. /var/run/mysqld의 소유자가 mysql인지 확인합니다. 그리고 -h localhost는 소켓을, -h 127.0.0.1은 TCP를 사용한다는 점도 진단에 유용합니다. 소켓 쪽만 문제인지 보려면 mysql -h 127.0.0.1 -u appuser -p로 TCP 접속을 시도해 보면 됩니다.

처음부터 다시 설치하고 싶을 때

설정을 이것저것 바꾸다가 상태가 꼬였고, 아직 지켜야 할 데이터가 없다면 깨끗하게 지우고 다시 설치하는 편이 빠를 수 있습니다. apt remove는 설정 파일과 데이터 디렉터리를 남기기 때문에, 다시 설치해도 이전 계정과 비밀번호가 그대로 살아납니다. 완전히 초기화하려면 purge와 함께 데이터 디렉터리까지 지워야 합니다.

아래 명령은 모든 데이터베이스를 영구적으로 삭제합니다. 필요한 데이터가 있다면 먼저 sudo mysqldump --all-databases > backup.sql로 백업하세요.

sudo systemctl stop mysql
sudo apt purge 'mysql-server*' 'mysql-client*' mysql-common
sudo apt autoremove
sudo rm -rf /var/lib/mysql /etc/mysql /var/log/mysql

그다음 처음의 sudo apt install mysql-server부터 다시 진행하면 root가 auth_socket인 초기 상태로 돌아옵니다.

설치가 안정되고 나면 다음 단계는 실제 운영에 필요한 설정입니다. 정기적인 mysqldump 백업을 cron이나 systemd 타이머로 걸어 두는 것, 서버 메모리에 맞게 innodb_buffer_pool_size를 조정하는 것이 대표적입니다. 버퍼 풀과 리두 로그가 어떤 역할을 하는지는 MySQL 엔진 이해하기에서, 느린 쿼리를 EXPLAIN으로 분석하는 방법은 MySQL EXPLAIN 쿼리 최적화에서 이어서 볼 수 있습니다.


같이 보면 좋은 글