본문으로 건너뛰기
안동민 개발노트 아이콘

안동민 개발노트

본문 시작

MySQL 8.4 실행 환경

설치 화면 대신 버전·엔진·sql_mode·시간대·문자 집합을 SQL로 확인해 재현 가능한 학습 환경을 만듭니다.

운영체제별 설치 화면은 금방 달라지고 GUI 연결이 성공해도 서버 버전과 세션 설정은 서로 다를 수 있습니다.

이 교재는 MySQL 8.4 LTS와 InnoDB를 기준으로 하며, 실행 환경의 상태를 캡처 이미지가 아니라 SQL 결과로 확인합니다.

설치 방식이 달라도 같은 진단 결과에 도달하는 것을 완료 기준으로 삼습니다.

로컬 설치나 mysql:8.4 컨테이너 중 어느 방식을 써도 됩니다.

중요한 것은 클라이언트 이름이 아니라 실제 연결된 서버의 VERSION(), 스토리지 엔진, 엄격 모드, 시간대, 연결 문자 집합을 동일하게 만드는 것입니다.

이 문서에서는 테이블을 만들지 않고 서버와 연결만 확인합니다.

Docker 경로는 시작 편의를 위해 빈 board_lab 데이터베이스를 미리 만들 수 있지만, 다음 문서에서 두 경로 모두 같은 CREATE DATABASE IF NOT EXISTS부터 실행합니다.


운영체제별 설치 방법

진단 SQL을 실행하려면 먼저 MySQL 서버와 명령줄 클라이언트가 필요합니다.

아래 세 경로는 서로 섞어 진행하는 단계가 아니라 운영체제와 학습 환경에 맞춰 하나만 선택하는 대안입니다.

어떤 경로를 택하든 완료 상태는 같습니다.

MySQL 8.4 서버가 실행 중이고, 클라이언트로 접속해 실제 서버 버전을 조회할 수 있어야 합니다.

Windows에서 Community 서버를 서비스로 실행하기

MySQL Community 서버 8.4 LTS 설치 프로그램에서 서버 구성 요소를 설치하고 루트 암호를 정합니다.

Windows 서비스 이름은 설치 선택에 따라 달라질 수 있으므로 먼저 실제 이름을 조회한 뒤 그 이름으로 시작합니다.

mysql.exe를 찾지 못하면 MySQL 서버의 bin 디렉터리를 현재 터미널의 경로에 추가합니다.

Windows 서비스와 client 확인
Get-Service -Name 'MySQL*'
Start-Service -Name 'MySQL84'

$env:Path += ';C:\Program Files\MySQL\MySQL Server 8.4\bin'
mysql --version
mysql -u root -p

Get-Service가 보여 준 이름이 MySQL84가 아니라면 Start-Service에도 조회된 이름을 사용합니다.

루트 암호는 명령 뒤에 붙이지 말고 클라이언트가 표시하는 암호 입력 프롬프트에서 입력합니다.

macOS에서 Homebrew 서비스로 실행하기

Homebrew를 사용하는 환경에서는 8.4 포뮬러를 설치하고 백그라운드 서비스로 시작할 수 있습니다.

버전이 있는 포뮬러는 실행 파일이 기본 경로에 연결되지 않을 수 있으므로 brew --prefix가 돌려준 실제 경로를 사용합니다.

macOS에서 MySQL 8.4 시작
brew install mysql@8.4
brew services start mysql@8.4

"$(brew --prefix mysql@8.4)/bin/mysql" --version
"$(brew --prefix mysql@8.4)/bin/mysql" -u root -p

초기 루트 인증 방식과 암호 설정은 포뮬러 안내에 따라 확인합니다.

서비스가 올라오지 않으면 brew services list와 MySQL 오류 로그를 먼저 보고, 같은 3306 포트를 사용하는 다른 MySQL·MariaDB가 있는지 점검합니다.

Docker로 호스트 설치와 데이터를 분리하기

기존 MySQL 설치와 충돌을 피하거나 실습 데이터를 쉽게 초기화하려면 컨테이너가 간단합니다.

아래 암호는 로컬 학습 전용 예시이며 공유 환경이나 운영 환경에서는 비밀 정보 저장소로 바꿔야 합니다.

MySQL 8.4 container 생성과 접속
docker volume create board-lab-mysql-data

docker run --name board-lab-mysql \
  --detach \
  --publish 3306:3306 \
  --env MYSQL_ROOT_PASSWORD=board-lab-local-8426 \
  --env MYSQL_DATABASE=board_lab \
  --volume board-lab-mysql-data:/var/lib/mysql \
  mysql:8.4

docker exec board-lab-mysql \
  mysqladmin ping -u root -pboard-lab-local-8426

docker exec -it board-lab-mysql \
  mysql -u root -pboard-lab-local-8426

mysqladmin 결과가 mysqld is alive이면 서버가 연결을 받을 준비가 된 것입니다.

3306 포트가 이미 사용 중이면 기존 서버를 중지하거나 호스트 쪽 포트만 3307:3306처럼 바꾸고, GUI와 애플리케이션도 3307로 접속합니다.

볼륨을 지우지 않는 한 컨테이너를 다시 만들어도 기존 데이터는 남습니다.

처음 실행할 SQL 읽기

mysql> 뒤에는 SQL 문장을 입력하고 세미콜론 ;으로 끝냅니다.

이 문서의 환경 확인에서는 아래 다섯 가지 표현만 사용합니다.

  • SELECT 값은 테이블이 없어도 값을 계산해 결과로 보여 줍니다.
  • VERSION()처럼 괄호가 붙은 이름은 입력을 계산해 값을 돌려주는 함수입니다.
  • AS server_version은 결과 열에 읽기 쉬운 별칭을 붙입니다.
  • @@port, @@session.time_zone처럼 @@로 시작하는 표현은 MySQL 서버나 현재 연결의 시스템 변수를 읽습니다.
  • SHOW DATABASES는 접속한 서버가 보여 줄 수 있는 데이터베이스 목록을 조회합니다.

서버는 MySQL 프로세스, 데이터베이스는 관련 테이블을 묶는 이름 공간, 세션은 클라이언트가 서버에 접속한 한 연결입니다.

sql_mode는 현재 세션에서 문자열·집계·잘못된 값을 얼마나 엄격하게 판단할지 정하는 MySQL 설정입니다.

UNION ALL은 여러 SELECT 결과를 위아래로 이어 붙입니다.

지금은 환경 진단 결과를 한 표로 보이는 데만 사용하고, 행 조회와 집합 규칙은 3장과 6장에서 다시 배웁니다.

가장 작은 문장부터 실행합니다.

연결이 SQL에 응답하는지 확인
SELECT 1 AS connection_ok;

connection_ok 열에 1이 나오면 이제 서버 버전과 접속 상태를 하나씩 읽을 수 있습니다.

접속한 서버가 학습 기준인지 확인하기

세 경로 중 하나로 mysql> 프롬프트에 들어왔다면 같은 SQL을 실행합니다.

최초 접속과 서버 식별
SELECT
  VERSION() AS server_version,
  @@version_comment AS distribution_name,
  CURRENT_USER() AS authenticated_account,
  @@port AS server_port;

SHOW DATABASES;
확인할 결과 모양
server_version | distribution_name | authenticated_account | server_port
8.4.x          | MySQL Community   | root@% 또는 root@localhost | 3306

버전이 8.4 계열이 아니거나 의도한 포트·계정이 아니라면 다음 SQL을 진행하지 않습니다.

특히 GUI가 저장한 오래된 연결과 방금 시작한 컨테이너가 서로 다른 서버일 수 있습니다.

버전·포트·계정을 확인한 뒤에야 아래 환경 진단으로 넘어갑니다.


버전과 세션 기본값의 함정

서버 버전을 고정하지 않고 sql_mode와 시간대를 확인하지 않은 채 예제를 실행합니다.

한 환경은 느슨한 GROUP BY를 허용하고 다른 환경은 1055를 내며, 같은 시각 리터럴도 세션 시간대에 따라 다르게 해석될 수 있습니다.

GUI의 녹색 연결 표시는 이 차이를 알려 주지 않습니다.

핵심 세션 상태를 숨긴 실행
SELECT 'status' AS setting_name, 'ready' AS setting_value
UNION ALL SELECT 'version', 'UNKNOWN'
UNION ALL SELECT 'sql_mode', 'UNKNOWN'
UNION ALL SELECT 'timezone', 'UNKNOWN'
UNION ALL SELECT 'charset', 'UNKNOWN';

준비 완료 한 줄은 서버 규칙의 증거가 아닙니다.

다른 버전·모드에서도 같은 출력이 나와 이후 오류를 환경과 SQL 중 어디서 찾을지 알 수 없습니다.

오류 실행 결과
setting_name | setting_value
status       | ready
version      | UNKNOWN
sql_mode     | UNKNOWN
timezone     | UNKNOWN
charset      | UNKNOWN

재현성은 명령이 한 번 성공했다는 뜻이 아니라 같은 입력과 규칙에서 같은 의미를 얻는 것입니다.

latest는 시간이 지나면 다른 주 버전을 가리킬 수 있고 전역 설정은 공유 서버의 다른 사용자에게 영향을 줍니다.

학습에서는 버전을 고정하고 필요한 세션 설정을 명시하며 실제 값을 출력합니다.


서버·데이터베이스·세션

MySQL 서버는 여러 데이터베이스와 연결을 가집니다.

@@global은 새 세션의 기본에 영향을 주고 @@session은 현재 연결의 실행 의미를 정합니다.

USE는 현재 데이터베이스를 선택할 뿐 계정·시간대·모드를 바꾸지 않습니다.

스키마 문자 집합은 저장 기본, 연결 문자 집합은 클라이언트와 서버 사이의 해석을 담당하므로 둘 다 확인합니다.

SQL 모드·@@ 변수·utf8mb4_0900_ai_ci는 MySQL 제품 기능입니다.

표준 SQL을 쓰더라도 오류 처리, 식별자 인용 규칙, 날짜 함수, 격리 기본값은 제품과 버전에 따라 다릅니다.

교재는 MySQL 8.4의 현재 동작을 명시하고 이식 가능한 부분과 MySQL 전용 선택을 각 문서에서 구분합니다.


환경 진단 쿼리

버전이 8.4 계열인지, InnoDB 지원, 엄격·ONLY_FULL_GROUP_BY, UTC 세션, utf8mb4 연결을 순서대로 확인합니다.

전역을 함부로 바꾸지 않고 현재 학습 연결에 필요한 값을 설정합니다.

SELECT 1은 서버가 가장 단순한 질의에 응답하는지 확인하는 연결 점검입니다.

MySQL 8.4 세션 진단과 고정
SELECT 1 AS connection_ok;
SELECT VERSION() AS mysql_version;
SELECT DATABASE() AS current_database;

SELECT engine, support, transactions
FROM information_schema.engines
WHERE engine = 'InnoDB';

SET SESSION sql_mode =
  'STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
SET SESSION time_zone = '+00:00';
SET NAMES utf8mb4 COLLATE utf8mb4_0900_ai_ci;

SELECT
  @@session.sql_mode AS session_sql_mode,
  @@session.time_zone AS session_time_zone,
  @@character_set_connection AS connection_charset,
  @@collation_connection AS connection_collation;

진단 결과가 문서의 기준과 맞아야 다음 실습으로 이동합니다.

컨테이너를 다시 만들거나 연결을 새로 열면 세션 설정을 다시 적용합니다.

개선 실행 결과
mysql_version        | 8.4.x
InnoDB support       | DEFAULT or YES
transactions         | YES
session_time_zone    | +00:00
connection_charset   | utf8mb4
current_database     | NULL 또는 board_lab

Docker 경로는 MYSQL_DATABASE=board_lab 때문에 데이터베이스가 이미 보일 수 있고, 로컬 설치 경로는 아직 NULL일 수 있습니다.

어느 쪽도 오류가 아닙니다.

이 단계의 완료 기준은 서버·엔진·세션 설정이며 board_lab 생성과 선택은 다음 문서에서 동일하게 수행합니다.

학습 데이터의 사람이 입력한 현지 시각은 이후 시간대 정책과 함께 저장합니다.

지금 UTC 세션을 쓰는 이유는 서버 위치에 따라 결과가 달라지는 것을 줄이기 위해서입니다.

DATETIME은 값 자체를 시간대 변환하지 않으므로 어떤 기준 시각인지 열 규칙에 적어야 합니다.

모드 문자열은 팀 요구에 맞게 버전 관리하고 새 버전에서 제거·추가된 모드를 확인합니다.


환경 정보 기록

중요 변수를 행 형태로 출력하면 환경별 설정 차이를 비교하기 쉽습니다.

지금은 연결 문자 집합을 확인하고, 다음 문서에서 board_lab를 만든 뒤 스키마 기본 문자 집합도 같은 쿼리로 확인합니다.

서버와 schema 환경 fingerprint
SELECT 'version' AS setting_name, VERSION() AS setting_value
UNION ALL SELECT 'database', COALESCE(DATABASE(), '<none>')
UNION ALL SELECT 'sql_mode', @@session.sql_mode
UNION ALL SELECT 'time_zone', @@session.time_zone
UNION ALL SELECT 'connection_charset', @@character_set_connection
UNION ALL SELECT 'connection_collation', @@collation_connection;

SELECT
  schema_name,
  default_character_set_name,
  default_collation_name
FROM information_schema.schemata
WHERE schema_name = 'board_lab';

설정이 모두 한 결과에 남아야 합니다.

아직 board_lab가 없다면 두 번째 조회는 0행이 정상입니다.

버전이 8.4가 아니면 예제를 억지로 맞추지 말고 기준 서버를 준비합니다.

컨테이너는 서버 프로세스와 데이터 볼륨을 재현하기 쉽게 하지만 백업·모니터링·업그레이드를 자동 해결하지 않습니다.

이미지 태그를 다이제스트로 더 강하게 고정할 수도 있으나 보안 갱신 수용 절차가 필요합니다.

로컬 설치도 패키지 버전과 설정을 기록하면 재현할 수 있습니다.

도구 선택보다 설치→접속→스키마 생성→예제 쿼리→삭제 후 복구 흐름을 다른 사람이 반복할 수 있는지가 중요합니다.

새 연결을 열어 세션 time_zonesql_mode가 되돌아가는지 확인하세요.

SET GLOBALSET SESSION의 권한·영향 범위를 비교하되 공유 서버에서는 전역을 바꾸지 않습니다.

연결 정렬 규칙을 다른 값으로 바꾼 뒤 문자열 비교 결과를 추측하고 원래 값으로 복원합니다.

MySQL 클라이언트와 Workbench가 같은 서버 포트·계정·스키마를 보는지도 CONNECTION_ID와 호스트 이름 정보로 확인합니다.

운영 설정은 마이그레이션이나 애플리케이션 시작에서 검증하고 기대와 다르면 조용히 진행하지 않게 합니다.

암호를 SQL 이력이나 저장소에 남기지 않고 비밀 정보 경계를 사용합니다.

루트는 설치·관리 계정이며 애플리케이션 계정은 최소 권한을 가집니다.

시간대 테이블이 필요한 이름 있는 시간대 함수와 단순 UTC 시차는 요구가 다르므로 배포 환경에서 시간대 데이터 존재도 확인합니다.

IF NOT EXISTS로 기존 데이터베이스를 재사용하면 예전 정렬 규칙·테이블이 남아 있을 수 있습니다.

볼륨을 재사용한 컨테이너도 깨끗한 환경이 아닙니다.

클라이언트 출력의 한글이 맞아 보여도 저장 바이트와 연결 변환이 올바른지 이모지·한글·ASCII 예제를 왕복 검증합니다.

식별자의 대소문자 민감성은 OS와 lower_case_table_names에 영향을 받을 수 있으므로 테이블 이름을 소문자 snake_case로 통일합니다.

이 환경 지문은 이후 모든 오류 조사에서 첫 기준입니다.

4장의 ONLY_FULL_GROUP_BY 오류, 8장의 트랜잭션 격리, 11장의 시간대 저장, 17장의 JSON 함수가 버전·세션 설정에 기대므로 실행 기록에 함께 붙입니다.

장별 SQL이 서로 다른 클라이언트에서 실행돼도 같은 회원 게시판 스키마와 설정을 보도록 합니다.


재현 가능한 실행 환경

판단 축확인할 질문
버전서버가 실제 MySQL 8.4 계열인가?
엔진InnoDB와 트랜잭션 지원을 확인했는가?
모드엄격·ONLY_FULL_GROUP_BY가 현재 세션에 있는가?
시간세션 시간대와 DATETIME 의미를 기록했는가?
문자스키마와 연결이 utf8mb4 규칙을 공유하는가?

GUI 접속 성공을 환경 완료로 보지 않습니다.

진단 SQL의 실제 출력이 기준과 맞고 새 연결에서도 초기화 절차가 반복될 때 준비됐다고 판단합니다.


연습 문제

새 MySQL 연결에서 환경 지문을 실행해 이전 세션과 다른 값을 찾으세요.

필요한 세션 설정만 다시 적용하고 board_lab의 엔진·정렬 규칙·현재 데이터베이스를 한 결과 기록으로 남기세요.

해설과 예시 답안

세션 변수는 연결마다 적용하므로 새 연결에서 다시 설정합니다.

데이터베이스와 테이블은 같은 서버·볼륨이면 유지되지만 현재 데이터베이스 선택은 연결마다 다시 해야 합니다.

SET SESSION sql_mode =
  'STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
SET SESSION time_zone = '+00:00';
SET NAMES utf8mb4 COLLATE utf8mb4_0900_ai_ci;

SELECT
  VERSION() AS version,
  DATABASE() AS db_name,
  @@session.time_zone AS tz,
  @@character_set_connection AS charset_name,
  @@collation_connection AS collation_name;

새 연결의 CONNECTION_ID가 다른지 확인하고 결과가 8.4·+00:00·utf8mb4 기준과 맞는지 비교합니다.

데이터베이스를 아직 만들지 않았다면 db_name은 NULL입니다.


핵심 정리

  • 설치 화면보다 실제 서버와 세션 변수를 SQL로 확인합니다.
  • 전역·세션·데이터베이스 설정의 범위를 구분합니다.
  • 버전·모드·시간대·문자 집합을 환경 지문으로 남깁니다.
  • 컨테이너와 GUI는 재현성 도구이지 설정 검증을 대신하지 않습니다.

다음 문서에서는 데이터베이스·테이블·행·열·값·키를 작은 표로 읽은 뒤 첫 CREATE·INSERT·SELECT를 실행합니다.