Haru Utils

데이터베이스 · 설치·설정 레시피

MySQL 설치와 기본 보안 설정

Ubuntu 지원 패키지로 MySQL을 설치하고, 로컬 우선 바인딩·초기 보안 점검·애플리케이션 전용 계정·서비스 검증까지 안전한 순서로 진행합니다.
MySQL 설치mysql_secure_installation3306 포트MySQL 보안Ubuntu MySQL
지원 환경Ubuntu Server 24.04 LTS 기본 mysql-server 패키지
예상 시간35
난이도중급
검토일2026-08-28

BEFORE YOU START

시작 전에 준비하세요

01

sudo 권한과 유지보수 가능한 SSH 접속

02

애플리케이션 DB·사용자 이름과 비밀번호 보관 수단

03

기존 MySQL/MariaDB가 있다면 호환성 검토와 검증된 백업

04

원격 접속이 필요하다면 허용 호스트·사설망·TLS 설계

권장 대상 Ubuntu에서 애플리케이션용 MySQL을 처음 구성하는 개발자·운영자

FOLLOW THE RECIPE

8단계 구성·점검 레시피

1
확인시스템을 변경하지 않는 점검 단계

Ubuntu와 MySQL 배포 경로 확인

이 레시피는 Ubuntu 기본 저장소 패키지를 사용합니다. Oracle MySQL APT 저장소의 특정 LTS 버전이 필요하면 저장소 전환·업그레이드를 별도 작업으로 계획합니다.

운영체제 확인
cat /etc/os-release
아키텍처 확인
dpkg --print-architecture
패키지 후보 확인
apt-cache policy mysql-server
초기화 시스템 확인
ps -p 1 -o comm=
  • Ubuntu LTS 기본 저장소의 MySQL 버전이 애플리케이션 요구를 충족한다.
  • MySQL과 MariaDB 패키지를 혼용하지 않는다.
  • PID 1이 systemd이다.
결과 읽기

Ubuntu 24.04 기본 mysql-server는 8.0 계열입니다. MySQL 8.4 LTS 같은 특정 계열이 필수라면 Oracle 공식 APT 저장소 절차와 마이그레이션 영향을 별도로 검토합니다.

다음 판단

기존 패키지·포트·데이터를 점검합니다.

2
확인시스템을 변경하지 않는 점검 단계

기존 MySQL·MariaDB와 3306 포트 점검

기존 DB를 덮어쓰거나 패키지 계열을 교체하지 않도록 설치 흔적·서비스·포트·용량을 확인합니다.

설치 패키지 확인
dpkg -l | grep -E '^ii  (mysql|mariadb)'
MySQL 서비스 확인
systemctl status mysql --no-pager
MariaDB 서비스 확인
systemctl status mariadb --no-pager
3306 포트 확인
sudo ss -ltnp | grep ':3306 '
데이터 경로 용량 확인
df -h /var/lib/mysql
  • 기존 DB 종류·버전·데이터 소유 팀을 확인했다.
  • 3306 포트 충돌이 없다.
  • 기존 데이터가 있다면 백업 파일과 복원 시험 결과가 있다.
결과 읽기

MariaDB 또는 다른 배포판이 설치되어 있으면 mysql-server를 바로 설치하지 않습니다. 데이터 포맷·인증 플러그인·패키지 충돌을 포함한 마이그레이션이 필요합니다.

다음 판단

신규 서버임이 확인되면 패키지를 설치합니다.

3
변경패키지·설정·서비스 상태가 달라지는 단계

MySQL 서버 설치

APT 변경사항을 미리 보고 Ubuntu 지원 mysql-server를 설치합니다. 설치 직후 실제 서버 버전과 서비스 상태를 확인합니다.

변경 단계입니다. 대상 서버, 백업 파일, 서비스 중단 영향과 바로 이전 상태로 돌아가는 방법을 다시 확인하세요.
패키지 인덱스 갱신
sudo apt update
변경사항 미리 보기
apt-get --simulate install mysql-server
MySQL 설치
sudo apt-get install -y mysql-server
클라이언트 버전 확인
mysql --version
서버 상태 확인
systemctl status mysql --no-pager
  • APT가 MariaDB나 의도하지 않은 패키지를 제거하지 않는다.
  • mysql 클라이언트 버전이 확인된다.
  • mysql 서비스가 시작되었다.
결과 읽기

설치가 실패하면 dpkg 잠금·디스크·패키지 의존성을 먼저 확인합니다. 데이터 디렉터리를 수동 삭제해 재시도하지 않습니다.

다음 판단

설정 백업과 로컬 우선 네트워크 설정을 진행합니다.

4
주의권한·연결·중단 영향을 확인할 단계

설정 백업과 애플리케이션 전용 계정

작업마다 고유한 <BACKUP_SUFFIX>로 기본 설정을 보존하고 MySQL은 로컬 인터페이스에만 바인딩합니다. 애플리케이션에는 root 대신 전용 DB와 계정을 부여합니다.

고유 백업 접미사 생성
date -u +%Y%m%dT%H%M%SZ
출력값을 이번 작업의 <BACKUP_SUFFIX>로 사용하고 변경 기록에 남깁니다.
MySQL 설정 백업
sudo cp --preserve=all --no-clobber /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf.<BACKUP_SUFFIX>.bak
<BACKUP_SUFFIX>를 방금 생성한 고유 값으로 교체합니다. 대상이 이미 있으면 덮어쓰지 말고 새 접미사를 만듭니다.
MySQL 설정 편집
sudoedit /etc/mysql/mysql.conf.d/mysqld.cnf
아래 항목을 기존 [mysqld] 구역에 반영하고 동일 옵션을 중복 선언하지 않습니다.
mysqld 그룹에 적용되는 옵션 확인
sudo my_print_defaults mysqld
옵션 파일에서 mysqld 그룹에 적용되는 옵션을 보여 주며, 읽은 파일 목록이나 전체 구문 검증 결과는 아닙니다.
초기 보안 도우미 실행
sudo mysql_secure_installation
root 원격 계정·익명 사용자·test DB 제거 여부를 확인합니다. 현재 인증 방식과 운영 정책을 이해한 뒤 답합니다.
관리자 로컬 접속
sudo mysql
설정 예시 · /etc/mysql/mysql.conf.d/mysqld.cnf
로컬 우선 네트워크 설정
[mysqld]
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1
원격 접속이 필요하면 공인 전체 주소가 아니라 서버의 사설 IP로 바꾸고, 특정 클라이언트 방화벽 규칙과 TLS를 함께 구성합니다.
설정 예시 · MySQL 콘솔
전용 DB와 로컬 애플리케이션 사용자 예시
CREATE DATABASE app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'app_user'@'localhost' IDENTIFIED BY RANDOM PASSWORD;
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'localhost';
SHOW GRANTS FOR 'app_user'@'localhost';
RANDOM PASSWORD가 한 번 반환한 값을 즉시 비밀 저장소에 보관합니다. DDL이 필요한 배포·마이그레이션 계정은 별도로 만들고 작업 범위와 기간을 제한하며 GRANT OPTION은 부여하지 않습니다.
  • mysqld.cnf 원본 백업이 있다.
  • bind-address와 mysqlx-bind-address가 루프백으로 제한된다.
  • 익명 사용자·불필요한 test DB·원격 root 계정을 제거했다.
  • 애플리케이션이 root가 아닌 전용 계정을 사용한다.
  • app_user에는 SELECT·INSERT·UPDATE·DELETE만 부여하고 DDL 권한을 분리했다.
  • 생성된 비밀번호를 코드·Git·셸 기록에 남기지 않았다.
결과 읽기

Ubuntu 패키지의 root는 로컬 socket 인증일 수 있습니다. 작동 중인 인증 방식을 무조건 비밀번호 방식으로 바꾸지 말고 관리 접속·자동화 영향을 먼저 확인합니다.

다음 판단

서비스를 재시작하고 로그를 확인합니다.

5
변경패키지·설정·서비스 상태가 달라지는 단계

서비스 적용과 부팅 자동 시작

MySQL 8.0.16 이상에서 제공하는 설정 검증을 먼저 통과한 뒤 네트워크 설정을 적용하고 서비스가 정상적으로 시작되는지 확인합니다. 이 검증은 서버를 정상 실행하지 않으며 초기화되지 않는 플러그인·스토리지 엔진 옵션까지 모두 검사하지는 않습니다.

변경 단계입니다. 대상 서버, 백업 파일, 서비스 중단 영향과 바로 이전 상태로 돌아가는 방법을 다시 확인하세요.
재시작 전 설정 검증
sudo mysqld --validate-config
MySQL 8.0.16 이상에서 오류가 없으면 종료 코드 0을 반환합니다. 첫 오류를 수정하고 다시 검증하며, 이 검사만으로 런타임 동작 검증을 대체하지 않습니다.
부팅 자동 시작 설정
sudo systemctl enable mysql
설정 적용
sudo systemctl restart mysql
서비스 상태 확인
systemctl status mysql --no-pager
최근 로그 확인
sudo journalctl -u mysql -n 100 --no-pager
  • mysqld --validate-config가 오류 없이 종료됐다.
  • mysql 서비스가 active 상태다.
  • 부팅 자동 시작이 enabled 상태다.
  • 로그에 설정 파일·InnoDB·권한 오류가 없다.
결과 읽기

unknown variable 오류는 옵션 이름이나 배치 위치 문제입니다. InnoDB 데이터 오류가 보이면 반복 재시작보다 백업·복구 절차로 전환합니다.

다음 판단

소켓·TCP·애플리케이션 계정으로 동작을 검증합니다.

6
확인시스템을 변경하지 않는 점검 단계

로컬 접속과 재부팅 검증

관리자 소켓 접속, 서버 응답, 리스닝 주소, 전용 계정 로그인을 따로 확인합니다.

서버 응답 확인
mysqladmin ping
서버 버전·바인딩 확인
sudo mysql -e "SELECT VERSION(); SHOW VARIABLES LIKE 'bind_address';"
3306 리스닝 주소 확인
sudo ss -ltnp | grep ':3306 '
전용 계정 로그인
mysql -h 127.0.0.1 -u app_user -p app_db
비밀번호는 -p 뒤에 붙이지 말고 프롬프트에서 입력합니다.
부팅 자동 시작 확인
systemctl is-enabled mysql
  • mysqladmin ping이 mysqld is alive를 반환한다.
  • 3306이 127.0.0.1에만 바인딩되어 있다.
  • app_user가 app_db에 로그인하고 허용된 작업만 수행한다.
  • 유지보수 재부팅 뒤 같은 검증을 반복했다.
결과 읽기

Access denied는 사용자명뿐 아니라 접속 host 부분과 인증 플러그인을 함께 확인합니다. timeout은 MySQL 계정보다 네트워크 경계를 먼저 확인합니다.

다음 판단

계정·네트워크·암호화 정책을 최종 확인합니다.

7
주의권한·연결·중단 영향을 확인할 단계

계정·포트·암호화 최종 점검

MySQL 계정은 사용자명과 접속 호스트의 조합입니다. '%' 호스트와 공인 3306 공개를 피하고 필요한 권한만 부여합니다.

계정과 접속 호스트 확인
sudo mysql -e "SELECT User,Host,plugin,account_locked FROM mysql.user ORDER BY User,Host;"
TLS 강제 설정 확인
sudo mysql -e "SHOW VARIABLES LIKE 'require_secure_transport';"
익명 계정 확인
sudo mysql -e "SELECT User,Host FROM mysql.user WHERE User='';"
방화벽 상태 확인
sudo ufw status numbered
외부 리스닝 재확인
sudo ss -ltnp | grep ':3306 '
  • 3306은 공인 인터넷에서 접근할 수 없다.
  • root 원격 계정과 익명 계정이 없다.
  • 애플리케이션 계정의 Host가 localhost 또는 승인한 단일 사설 호스트로 제한된다.
  • 애플리케이션 계정에 전역 권한이나 GRANT OPTION을 주지 않는다.
  • 원격 연결에는 TLS 또는 VPN·SSH 터널을 적용한다.
  • 백업과 설정 파일에 포함된 자격 증명 접근 권한을 제한한다.
결과 읽기

비밀번호가 있어도 '%'@사용자와 공개 3306 조합은 안전한 기본값이 아닙니다. 네트워크·호스트·권한·암호화를 겹쳐 적용합니다.

다음 판단

복구 가능한 롤백 명령과 변경 기록을 남깁니다.

8
주의권한·연결·중단 영향을 확인할 단계

설정 복원과 데이터 보존 제거

설정 변경 문제라면 백업 목록과 변경 기록을 대조해 복원할 <BACKUP_SUFFIX>를 명시적으로 고른 뒤 이전 mysqld.cnf를 복원합니다. 신규 설치 제거 시에도 데이터 디렉터리를 자동 삭제하는 purge는 사용하지 않습니다.

서비스 중지
sudo systemctl stop mysql
설정 백업 후보 목록 확인
sudo find /etc/mysql/mysql.conf.d -maxdepth 1 -type f -name 'mysqld.cnf.*.bak' -printf '%TY-%Tm-%Td %TH:%TM:%TS %p\n' | sort
변경 기록·파일 시각·내용을 대조해 복원할 한 개의 <BACKUP_SUFFIX>를 고릅니다. 최신 파일을 자동 선택하지 않습니다.
선택한 설정 백업 확인
sudo test -f /etc/mysql/mysql.conf.d/mysqld.cnf.<BACKUP_SUFFIX>.bak
<BACKUP_SUFFIX>를 명시적으로 고른 값으로 교체하고 파일 내용을 확인한 뒤에만 복원합니다.
백업 설정 복원
sudo cp --preserve=all /etc/mysql/mysql.conf.d/mysqld.cnf.<BACKUP_SUFFIX>.bak /etc/mysql/mysql.conf.d/mysqld.cnf
복원 설정 검증
sudo mysqld --validate-config
종료 코드 0을 확인한 뒤에만 서비스를 시작합니다.
복원 후 서비스 시작
sudo systemctl start mysql
완전한 신규 설치일 때 패키지만 제거
sudo apt-get remove mysql-server
데이터와 /var/lib/mysql 보존 여부를 확인하고 purge나 수동 삭제는 하지 않습니다.
  • 롤백 전 현재 설정도 별도로 보존했다.
  • 백업 목록과 변경 기록을 대조해 복원할 <BACKUP_SUFFIX>를 명시적으로 선택했다.
  • 선택한 백업 존재와 복원 설정 검증 성공을 확인한 뒤 서비스를 시작했다.
  • 복원 후 mysqladmin ping과 핵심 쿼리가 정상이다.
  • 계정·권한 변경이 있다면 감사 기록을 남겼다.
  • 패키지 제거 전 백업·복원 책임자 승인을 받았다.
결과 읽기

설정 복원 후에도 InnoDB 오류가 계속되면 초기화하지 말고 백업·복구 전문가와 로그를 검토합니다.

다음 판단

포트·서비스·디스크 문제는 연결된 장애 대응 가이드에서 이어서 확인합니다.

SECURITY CHECK

운영 전 마지막 보안 점검

  • 3306을 공인 인터넷에 직접 공개하지 않는다.
  • root 원격 로그인과 익명 사용자를 허용하지 않는다.
  • 애플리케이션 전용 계정의 Host와 권한을 최소화한다.
  • 비밀번호는 명령줄·소스·Git에 남기지 않는다.
  • 원격 접속 시 TLS 또는 암호화 터널을 사용한다.

COMMON ERRORS

자주 막히는 지점

Access denied for user 오류

증상
비밀번호가 맞는 것 같지만 특정 호스트에서 로그인이 거부됩니다.
가능한 원인
MySQL의 User와 Host 조합, 인증 플러그인 또는 권한 대상 DB가 실제 연결과 다릅니다.
확인 순서
관리자 소켓으로 mysql.user와 SHOW GRANTS를 확인하고 필요한 특정 Host 계정만 수정합니다.

MySQL 서비스 시작 실패

증상
설정 변경 후 mysql.service가 failed 상태가 됩니다.
가능한 원인
잘못된 옵션, 포트 충돌, 권한 또는 InnoDB 데이터 오류가 흔합니다.
확인 순서
journalctl의 첫 오류와 3306 점유를 확인하고, 데이터 오류가 아니면 백업 설정으로 복원합니다.
트러블슈팅으로 이어보기

원격 연결 시간 초과

증상
로컬에서는 접속되지만 다른 서버에서는 응답이 없습니다.
가능한 원인
bind-address, UFW·보안 그룹, 라우팅 중 하나가 연결을 차단합니다.
확인 순서
공인 전체 바인딩으로 우회하지 말고 사설 IP 리스닝과 허용 경로를 안쪽부터 확인합니다.
트러블슈팅으로 이어보기

PRIMARY REFERENCES

공식 문서

설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.

도구 빠른 검색

최근 사용한 도구를 다시 열거나, 이름과 기능으로 검색하세요.

검색어와 도구의 입력·결과는 저장하지 않습니다.

↑↓ 이동 · Enter 열기 · Esc 닫기