Sửa lỗi MySQL ERROR 1406: Data Too Long for Column khi INSERT hoặc UPDATE

beginner🗄️ MySQL2026-03-18| MySQL 5.7 / 8.0+, MariaDB 10.x — Linux, Windows, macOS

Error Message

ERROR 1406 (22001): Data too long for column 'username' at row 1
#mysql#varchar#data-truncation#schema#column-length

Mô tả lỗi

Bạn đang chạy lệnh INSERT hoặc UPDATE và MySQL báo lỗi:

ERROR 1406 (22001): Data too long for column 'username' at row 1

Lỗi này có nghĩa là giá trị bạn đang cố lưu vượt quá giới hạn mà kiểu dữ liệu của cột cho phép. Một cột VARCHAR(50) sẽ từ chối bất kỳ giá trị nào dài hơn 50 ký tự — không có ngoại lệ. Nếu lỗi này xuất hiện lúc 2 giờ sáng từ một câu lệnh insert trên môi trường production, đây là cách xử lý nhanh nhất.

Nguyên nhân

Thường do một trong ba nguyên nhân sau:

  • Cột được định nghĩa quá hẹp so với dữ liệu thực tế (ví dụ: VARCHAR(50) nhưng người dùng dán chuỗi 200 ký tự)
  • Có gì đó thay đổi ở phía trước — giới hạn ký tự của form bị xóa, hoặc API bắt đầu trả về chuỗi dài hơn
  • Chế độ STRICT_TRANS_TABLES đang bật (mặc định từ MySQL 5.7.5), sẽ từ chối các giá trị vượt kích thước thay vì tự động cắt bớt

Bước 1: Kiểm tra độ dài hiện tại của cột

Đừng đoán mò — hãy kiểm tra cột đang được định nghĩa như thế nào:

DESCRIBE users;
-- hoặc
SHOW COLUMNS FROM users LIKE 'username';

Để xem thêm thông tin bao gồm charset:

SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'your_database'
  AND TABLE_NAME = 'users'
  AND COLUMN_NAME = 'username';

Sau đó kiểm tra độ dài chính xác của giá trị gây lỗi:

SELECT LENGTH('the_value_that_failed');

Biết cả hai con số sẽ cho bạn biết chính xác cần mở rộng bao nhiêu.

Bước 2: Tăng độ dài cột (Cách sửa được khuyến nghị)

Giải pháp gọn nhất: mở rộng cột để phù hợp với dữ liệu thực tế.

ALTER TABLE users MODIFY COLUMN username VARCHAR(255) NOT NULL;

VARCHAR(255) đủ cho hầu hết các trường username và họ tên. Với phần bio, mô tả hoặc bất kỳ nội dung không giới hạn nào, hãy bỏ VARCHAR và dùng TEXT:

ALTER TABLE users MODIFY COLUMN bio TEXT;

Với bảng lớn, ALTER TABLE có thể khóa bảng trong suốt quá trình thực thi. Với bảng 10 triệu dòng trở lên, đó là vài phút downtime. Hãy dùng pt-online-schema-change hoặc instant DDL của MySQL 8.0:

-- MySQL 8.0: chỉnh sửa cột tức thì (không cần rebuild lại bảng)
ALTER TABLE users
  MODIFY COLUMN username VARCHAR(255) NOT NULL,
  ALGORITHM=INSTANT;

INSTANT hoạt động tốt với việc tăng độ dài VARCHAR trong hầu hết trường hợp, nhưng không hỗ trợ thay đổi kiểu dữ liệu hay chuyển đổi charset.

Bước 3: Cắt bớt dữ liệu (Nếu chấp nhận mất dữ liệu)

Chưa thể động vào schema ngay bây giờ? Bạn có thể cắt bớt giá trị khi insert:

INSERT INTO users (username) VALUES (LEFT('some_very_long_username_here', 50));

Hoặc cắt bớt trong code ứng dụng trước khi dữ liệu đến database. Dù cách nào thì đây cũng chỉ là giải pháp tạm thời — hãy sửa schema khi mọi thứ ổn định trở lại.

Bước 4: Tắt Strict Mode (Lối thoát tạm thời)

Import hàng loạt đang thất bại và bạn chấp nhận việc tự động cắt bớt dữ liệu trong lúc này? Bạn có thể tắt strict mode chỉ cho session hiện tại:

SET SESSION sql_mode = REPLACE(@@SESSION.sql_mode, 'STRICT_TRANS_TABLES', '');

-- Chạy các câu lệnh insert ở đây

-- Bật lại khi xong
SET SESSION sql_mode = @@GLOBAL.sql_mode;

Không bao giờ tắt strict mode toàn cục trên môi trường production. Strict mode chính là thứ ngăn dữ liệu xấu làm hỏng bảng của bạn. Chỉ dùng cách này như một biện pháp nhất thời trong quá trình migration hoặc import dữ liệu có kiểm soát.

Xác nhận đã sửa xong

Sau khi mở rộng cột, kiểm tra lại định nghĩa mới:

SHOW COLUMNS FROM users LIKE 'username';
-- Phải hiển thị VARCHAR(255) hoặc giá trị bạn đã đặt

Chạy lại câu truy vấn bị lỗi trước đó:

INSERT INTO users (username) VALUES ('the_value_that_was_failing');
-- Query OK, 1 row affected

Xác nhận dữ liệu đã được lưu đúng:

SELECT username, LENGTH(username) FROM users ORDER BY id DESC LIMIT 1;

Xử lý trong code ứng dụng

Gặp lỗi từ database là cách tệ nhất để phát hiện ra input chưa được validate. Hãy thêm kiểm tra độ dài trước khi gọi DB:

# Ví dụ Python — validate trước khi insert
if len(username) > 255:
    raise ValueError(f"Tên người dùng quá dài: {len(username)} ký tự")

Muốn áp dụng quy tắc ở tầng database luôn? MySQL 8.0.16+ hỗ trợ CHECK constraints:

ALTER TABLE users
  ADD CONSTRAINT chk_username_length CHECK (CHAR_LENGTH(username) <= 255);

Điều này đảm bảo thông báo lỗi rõ ràng bất kể dữ liệu đến từ đâu — ORM, câu truy vấn thô hay kết nối trực tiếp.

Lưu ý về vấn đề Charset

Đang lưu emoji hoặc ký tự CJK? Charset ảnh hưởng đến lượng bộ nhớ thực tế mỗi ký tự chiếm. Với utf8mb4, một emoji có thể chiếm 4 byte. Cột VARCHAR(255) lưu được 255 ký tự nhưng có thể dùng tới 1020 byte — điều này quan trọng với giới hạn độ dài khóa index.

Kiểm tra charset của cột:

SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'your_database'
  AND TABLE_NAME = 'users'
  AND COLUMN_NAME = 'username';

Nếu bạn đang dùng utf8mb4 và gặp giới hạn index prefix (giới hạn key mặc định của InnoDB là 767 byte trong MySQL 5.7, 3072 byte trong 8.0 với innodb_large_prefix), hãy dùng prefix index hoặc rút ngắn định nghĩa cột.

Tóm tắt nhanh

  • Sửa nhanh (thay đổi schema): ALTER TABLE t MODIFY COLUMN col VARCHAR(255);
  • Kiểm tra kích thước hiện tại: SHOW COLUMNS FROM table LIKE 'column';
  • Giải pháp tạm thời: SET SESSION sql_mode = REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '');
  • Với văn bản rất dài: chuyển từ VARCHAR sang TEXT
  • Bảng lớn trên production: dùng ALGORITHM=INSTANT hoặc pt-online-schema-change

Related Error Notes