웹 서비스를 운영하다가 사용자가 이모지(😊, 🚀)나 특정 다국어 문자를 입력하고 저장할 때 MySQL ERROR 1366 (HY000): Incorrect string value 에러가 발생하며 데이터 저장이 튕기는 현상을 경험해봤을까?
다만 대부분의 개발자들은 이 에러의 정확한 원인이 MySQL 기본 utf8 인코딩의 3바이트 제한이라는 사실을 모른 채, 단지 사용자 입력값에서 이모지를 강제로 정제해 버리는 임시방편을 선택하곤 한다.
이번에는 ERROR 1366이 왜 발생하는지 그 구조적 원인부터, 데이터 손실 없이 utf8mb4로 DB와 테이블 설정을 변경하고 애플리케이션 커넥션까지 완벽하게 처리하는 방법을 정리해서 소개하겠다.
MySQL에서 traditional한 utf8 문자셋(character set)은 사실 표준 UTF-8 인코딩이 아닙니다. MySQL 5.5 이전부터 구현되었던 특수 스펙으로, 문자당 최대 3바이트(utf8mb3)까지만 저장할 수 있도록 제한되어 있습니다.
그러나 현대 웹 환경에서 흔히 사용되는 이모지(Emoji), 일부 고대 문자, 확장 한자 등은 4바이트 크기를 차지합니다. 3바이트 제한이 걸린 utf8 컬럼에 4바이트 크기의 문자 데이터를 입력하려고 하면 MySQL 데이터베이스 엔진이 이를 수용하지 못하고 ERROR 1366 (HY000): Incorrect string value 예외를 던지며 쿼리 실행을 중단시킵니다.
| 항목 | utf8 (utf8mb3) | utf8mb4 |
|---|---|---|
| 바이트 크기 | 가변 1~3 바이트 | 가변 1~4 바이트 |
| 이모지(Emoji) 지원 | 불가 (ERROR 1366 발생) | 완벽 지원 (😊, 🚀, 💻 등) |
| 표준 규격 | MySQL 전용 제한 스펙 | 국제 표준 UTF-8 완전 준수 |
| 권장 여부 | 사용 지양 (Deprecated) | 최신 MySQL/MariaDB 기본 권장 |
이 문제를 근본적으로 해결하려면 데이터베이스, 테이블, 그리고 컬럼의 캐릭터셋을 4바이트 지원 인코딩인 utf8mb4로 변경해야 합니다. 정렬 방식(Collation)은 주로 utf8mb4_unicode_ci 또는 utf8mb4_general_ci를 사용합니다.
기존 데이터베이스의 기본 문자셋을 utf8mb4로 지정하는 쿼리입니다.
ALTER DATABASE my_database CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
테이블 내에 존재하는 기존 VARCHAR, TEXT 컬럼들의 인코딩까지 안전하게 한 번에 변환하기 위해서는 CONVERT TO 구문을 실행해야 합니다.
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
DB 테이블 설정을 올바르게 바꿨더라도 백엔드 애플리케이션에서 데이터베이스에 접속할 때 연결 인코딩을 utf8로 유지하고 있다면 여전히 ERROR 1366이나 문자가 깨지는 장애가 발생합니다. PHP PDO 환경을 기준으로 잘못된 예시와 올바른 작성 방식을 비교해 봅시다.
✗ 잘못된 코드 (커넥션 charset 옵션이 utf8로 지정된 경우)
<?php
// DB 테이블을 utf8mb4로 변경했어도 커넥션 DSN이 utf8로 되어 있다면 문제가 발생함
$dsn = "mysql:host=localhost;dbname=test_db;charset=utf8";
$pdo = new PDO($dsn, "dbuser", "password");
// 4바이트 이모지가 포함된 문자열 저장 시도
$stmt = $pdo->prepare("INSERT INTO comments (content) VALUES (:content)");
// PDOException: SQLSTATE[HY000]: General error: 1366 Incorrect string value 발생!
$stmt->execute([':content' => '안녕하세요! 반갑습니다 😊']);
?>✓ 올바른 코드 (PDO 커넥션 및 쿼리 처리)
<?php
// DSN 매개변수에 charset=utf8mb4 를 명확히 설정
$dsn = "mysql:host=localhost;dbname=test_db;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
];
$pdo = new PDO($dsn, "dbuser", "password", $options);
// 이모지가 포함된 텍스트 정상 저장
$stmt = $pdo->prepare("INSERT INTO comments (content) VALUES (:content)");
$stmt->execute([':content' => '안녕하세요! 반갑습니다 😊']);
echo "데이터 저장 성공!";
?>결과 / 출력값
데이터 저장 성공!
(DB 조회 시 '안녕하세요! 반갑습니다 😊' 텍스트와 이모지가 손상 없이 깔끔하게 저장됨)
utf8mb4로 인코딩 전환을 진행할 때 자주 마주치게 되는 실무 이슈와 예방법입니다.
✗ **인덱스 길이 제한 오류 (`Specified key was too long; max key length is 767 bytes`)**
MySQL InnoDB 기본 엔진의 인덱스 키 최대 길이는 767바이트입니다. 기존 utf8 기준에서는 VARCHAR(255) (255 × 3 = 765바이트)에 인덱스를 걸 수 있었으나, utf8mb4로 변환 시 (255 × 4 = 1020바이트)가 되면서 테이블 ALTER 실행 시 에러가 발생할 수 있습니다.
✓ **해결책**: 인덱스가 부여된 컬럼의 길이를 VARCHAR(191) 이하(191 × 4 = 764바이트)로 줄이거나, MySQL 5.7 이상 및 MariaDB 환경에서 innodb_large_prefix 옵션을 활성화하세요.
매 커넥션마다 SET NAMES utf8mb4 구문을 명시하지 않더라도 MySQL 데몬 자체가 기본적으로 utf8mb4를 채택하도록 설정해 두는 것이 안전합니다.
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
MySQL ERROR 1366은 이모지와 같은 4바이트 가변 문자를 수용하지 못하는 구형 3바이트 utf8 인코딩을 그대로 사용할 때 발생하는 대표적인 데이터베이스 장애입니다.
DB 및 테이블 구조 변경부터 시작해 백엔드 애플리케이션의 커넥션 파라미터, 그리고 MySQL 서버 my.cnf 설정까지 3박자를 통합하여 utf8mb4로 적용하는 습관이 중요하다. 이 글의 ALTER 구문과 PDO charset 설정을 참고해 데이터베이스 환경을 재점검하고 전환을 진행하면, 입력 데이터 유실 없이 이모지와 다양한 다국어를 지원하는 안정적인 서비스를 구축할 수 있을 것이다.