분명 한글을 넣었는데 조회하면 ???로 나오거나, 이모지를 저장하려는 순간 Incorrect string value 에러가 터집니다. 코드는 멀쩡한데 데이터만 깨진다면 원인은 거의 항상 문자셋(charset)과 콜레이션(collation) 설정입니다. 특히 오래된 MySQL의 utf8은 한글은 되지만 이모지 같은 4바이트 문자를 저장하지 못합니다.
utf8과 utf8mb4의 차이
MySQL의 utf8은 이름과 달리 진짜 UTF-8이 아닙니다. 문자당 최대 3바이트만 저장하는 반쪽짜리라, 4바이트가 필요한 이모지나 일부 한자가 들어오면 실패합니다.
| 항목 | utf8 (utf8mb3) | utf8mb4 |
|---|---|---|
| 문자당 최대 바이트 | 3바이트 | 4바이트 |
| 한글 | 가능 | 가능 |
| 이모지·보조문자 | 불가 (에러) | 가능 |
| 권장 콜레이션 | — | utf8mb4_unicode_ci 또는 utf8mb4_0900_ai_ci |
콜레이션은 정렬·비교 규칙입니다. _ci는 대소문자 구분 안 함(case-insensitive), _bin은 바이트 그대로 비교입니다. 일반 텍스트는 utf8mb4_unicode_ci가 무난합니다.
어디가 깨지는지 진단
문자셋은 서버, DB, 테이블, 컬럼, 그리고 연결(connection) 까지 단계마다 따로 설정됩니다. 한 군데라도 어긋나면 깨집니다.
SQL
-- 현재 DB·테이블 문자셋 확인
SHOW VARIABLES LIKE 'character_set%';
SHOW CREATE TABLE users;
-- 연결 단계 문자셋 확인
SHOW VARIABLES LIKE 'character_set_client';
character_set_client가 latin1이면 애플리케이션이 보낸 한글이 연결 단계에서 이미 깨집니다. 테이블이 utf8mb4라도 소용없습니다.
전환 순서
- 서버 기본값 설정 —
my.cnf에 다음을 넣고 재시작합니다.
로컬 터미널
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
- 기존 테이블 변환 — 데이터까지 함께 변환하려면
CONVERT TO를 씁니다.
SQL
ALTER TABLE users
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 연결 문자셋 지정 — 드라이버 URL이나 DSN에 명시합니다. JDBC는
characterEncoding=utf8, Nodemysql2는charset: 'utf8mb4'를 넣습니다. - 검증 —
INSERT후 이모지가 그대로 조회되는지 확인합니다.
이미 깨진 채로 저장된 데이터는 CONVERT TO로 되살릴 수 없는 경우가 많습니다. 깨진 행은 원본에서 다시 적재해야 합니다.
요점 정리
- MySQL
utf8은 3바이트 한계 — 이모지·일부 문자는utf8mb4라야 저장된다. - 깨짐은 서버·테이블·컬럼·연결 중 한 단계만 어긋나도 발생한다.
- 진단은
SHOW VARIABLES LIKE 'character_set%'로 연결 문자셋부터 확인한다. - 전환은 서버 기본값 →
ALTER TABLE ... CONVERT TO→ 연결 문자셋 순서로 한다.
문자셋·콜레이션을 직접 바꿔보며 깨짐 전후를 확인하는 실습은 데이터베이스 트랙에서 회원가입 없이 무료로 할 수 있습니다.