Fixing the 767-Byte Index Limit in MySQL (utf8mb4)

intermediate๐Ÿ—„๏ธ MySQL2026-04-22| MySQL 5.5, 5.6, or early 5.7; MariaDB versions prior to 10.2.2. Often found on legacy Ubuntu 14.04/16.04 servers or older AWS RDS instances.

Error Message

ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
#mysql#utf8mb4#database-administration#innodb#sql-errors

The Error Message

When migrating to utf8mb4 or creating tables with VARCHAR(255) indexes, you might run into this frustrating bottleneck:

ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

This typically appears during an ALTER TABLE or CREATE TABLE operation. It is a common pain point for developers upgrading from the old 3-byte utf8 (utf8mb3) to full 4-byte utf8mb4 support, which is necessary for emojis and mathematical symbols.

The Root Cause: Why 767 Bytes?

The math behind the error is straightforward. In older versions of MySQL using the InnoDB Antelope format, index keys were capped at exactly 767 bytes.

Compare how different character sets use that space:

  • Legacy utf8 (utf8mb3): 1 character = max 3 bytes. 255 characters * 3 bytes = 765 bytes. This fits just under the limit.
  • Modern utf8mb4: 1 character = max 4 bytes. 255 characters * 4 bytes = 1020 bytes. This overshoots the 767-byte limit, causing the engine to reject the index.

MySQL always reserves the maximum possible space for an index. Even if your current data is simple alphanumeric text, the database prepares for the worst-case 4-byte character.

Fix 1: Switch the Row Format to DYNAMIC

The most effective solution is switching to the Barracuda file format. This format supports "large prefixes," allowing indexes up to 3072 bytes. To use it, you must set the table's row format to DYNAMIC or COMPRESSED.

Updating a single table:

ALTER TABLE your_table_name 
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, 
ROW_FORMAT=DYNAMIC;

For new tables, include the format in your CREATE statement:

CREATE TABLE example (
    id INT PRIMARY KEY,
    slug VARCHAR(255) NOT NULL,
    UNIQUE KEY (slug)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

Fix 2: The '191' Rule (Quick Fix)

If you're working on a locked-down system where you can't change global server variables, try the "191" rule. Since 767 divided by 4 equals 191.75, a VARCHAR(191) column is the largest possible size that fits in a legacy index.

ALTER TABLE users MODIFY username VARCHAR(191) CHARACTER SET utf8mb4;

This is often the safest path for legacy applications. You keep the 767-byte limit but shrink the column enough to allow 4-byte characters without crashing the schema.

Fix 3: Global System Configuration (MySQL 5.6)

For those managing dozens of tables, updating each one manually is tedious. Instead, you can change the server's default behavior if you have SUPER privileges. Run these commands to enable large prefixes globally:

SET GLOBAL innodb_file_format = Barracuda;
SET GLOBAL innodb_file_per_table = ON;
SET GLOBAL innodb_large_prefix = ON;

Note that while this allows larger indexes, you still need to ensure your tables use ROW_FORMAT=DYNAMIC to actually take advantage of the new limit.

Verification: How to confirm it's fixed

Never assume a migration worked just because there wasn't an error. Verify the underlying structure with these three checks:

  • Check Row Format: Run SHOW TABLE STATUS LIKE 'your_table_name'\G and look for Row_format: Dynamic.
  • Check Collation: Run SHOW FULL COLUMNS FROM your_table_name; to ensure you see utf8mb4_unicode_ci.
  • Test the Charset: Try inserting a 4-byte character like an emoji: INSERT INTO your_table_name (column) VALUES ('๐Ÿš€');.

Prevention & Best Practices

The ultimate fix is upgrading to MySQL 8.0+ or MariaDB 10.2+. In these versions, DYNAMIC is the default row format, and large prefixes are enabled out of the box. You will rarely see this error on modern stacks unless you try to index a column larger than 768 characters.

When handling complex migrations, I've found that characters can sometimes get mangled in transit before they even hit the database. If you're debugging weird string behavior, ToolCraft's URL Encoder/Decoder is a handy, privacy-focused way to verify your data encoding directly in the browser. It helps ensure your strings are clean before you start troubleshooting DB indexes.

Summary Checklist:

  • Best case: Upgrade to MySQL 8.0.
  • On 5.6: Enable innodb_large_prefix and set ROW_FORMAT=DYNAMIC.
  • Last resort: Drop VARCHAR(255) down to VARCHAR(191) for indexed columns.

Related Error Notes