1118

Fix MySQL ERROR 1118: Row size too large (InnoDB)

MySQL throws ERROR 1118 when a table's row exceeds 65,535 bytes. Shrink columns, change formats, or convert to DYNAMIC row format to fix it.

Quick answer: Switch the table to DYNAMIC row format or convert large VARCHARs to TEXT, then recreate the table.

I know this error is infuriating — you write a perfectly reasonable CREATE TABLE statement, hit Enter, and MySQL throws ERROR 1118 (42000): Row size too large. The table looks fine, the columns aren't insane, but MySQL refuses. This tripped me up the first time I saw it too, back when I was running a help desk blog and a client's product catalog kept failing to import.

Here's what's happening: MySQL has a hard limit of 65,535 bytes per row. That limit applies to the sum of all column lengths, regardless of storage engine. For InnoDB, the actual bottleneck is often the row format. In the older COMPACT format, each VARCHAR column reserves its full declared length in the row's fixed-size portion, so a table with many VARCHAR(255) columns can blow past the limit quickly.

The fix isn't to redesign your entire schema — it's to change how InnoDB stores the row. Let me walk you through the steps that actually work.

Fix Step 1: Check Your Current Row Format

First, see what row format your table is using. If you get the error during CREATE TABLE, you can check the server default:

SHOW VARIABLES LIKE 'innodb_default_row_format';

If it says COMPACT or REDUNDANT, that's your problem. Those formats store all variable-length columns in the fixed-size part of the row, and they hit the 65,535-byte ceiling way faster.

Fix Step 2: Create the Table with DYNAMIC Row Format

You can override the default per-table. Wrap your CREATE TABLE statement with ROW_FORMAT=DYNAMIC:

CREATE TABLE large_table (
  id INT NOT NULL AUTO_INCREMENT,
  col1 VARCHAR(255),
  col2 VARCHAR(255),
  -- ... more columns ...
  PRIMARY KEY (id)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

DYNAMIC format stores long variable-length columns off-page, so only a 20-byte pointer stays in the row. That frees up massive space. I've seen tables with 30+ VARCHAR(255) columns pass with DYNAMIC when COMPACT failed at column 18.

Fix Step 3: If You Already Have the Table, ALTER It

If the table already exists (maybe you created it before the error appeared in another context), you can convert it:

ALTER TABLE large_table ROW_FORMAT=DYNAMIC;

This rebuilds the table in the background (with online DDL, it's usually non-blocking, but check your MySQL version — 5.7+ handles this well).

Alternative Fix: Convert Big VARCHARs to TEXT

If DYNAMIC row format isn't an option — say you're on MySQL 5.6 and can't change the default — the next best thing is to swap your largest VARCHAR columns for TEXT. TEXT and BLOB columns are always stored off-page in InnoDB, so they don't count toward the 65,535-byte row limit.

CREATE TABLE large_table (
  id INT NOT NULL AUTO_INCREMENT,
  col1 VARCHAR(255),
  col2 TEXT,  -- was VARCHAR(1000)
  PRIMARY KEY (id)
) ENGINE=InnoDB;

Be aware: TEXT columns can't have a default value (unless you're on MySQL 8.0.13+ with expression defaults), and they're stored differently, which can affect performance. But it's a solid workaround.

Alternative Fix: Split the Table

Sometimes the schema design is the real problem. If you have hundreds of columns, or if the columns are semantically separate, consider splitting into two tables with a one-to-one relationship. I've done this for legacy apps where the original developer dumped every field into one table. It's more work, but it's the cleanest long-term fix.

For example, put the frequently accessed columns in the main table, and the rarely used or huge text fields in a secondary table joined by primary key.

Prevention: Set DYNAMIC as the Default

Once you've fixed the immediate error, stop it from happening again. Set DYNAMIC as the default row format for all new InnoDB tables:

SET GLOBAL innodb_default_row_format = DYNAMIC;

Or in your my.cnf / my.ini file, under the [mysqld] section:

innodb_default_row_format = DYNAMIC

This requires a restart to take effect if you put it in the config file, but it's worth it. MySQL 8.0 defaults to DYNAMIC anyway, so if you're on 5.7 or earlier, this is your safety net.

One More Thing: Watch Out for the 255-Character Trap

Here's a subtle gotcha: VARCHAR(255) is a common choice because it's the max for an indexed column with utf8mb4 (which uses 4 bytes per character). But with utf8mb4, VARCHAR(255) actually reserves 1,020 bytes in the row (255 × 4). So 60 of those columns max out the row. If you don't need 255 characters, drop to VARCHAR(191) or VARCHAR(100). It's an easy win.

Note: The 65,535-byte limit applies to the row size, not the storage engine. Even with DYNAMIC, the row can't exceed that total — but because off-page columns only count 20 bytes each, you'll rarely hit it in practice.

Here's a quick reference table to help you decide:

SituationBest Fix
MySQL 5.7+ / 8.0Use ROW_FORMAT=DYNAMIC
MySQL 5.6 or olderConvert VARCHAR to TEXT
Too many columnsSplit the table

If you've followed these steps and still hit the error, double-check that you're not using a weird charset like utf8mb4 on a huge number of columns. Sometimes the fix is as simple as reducing a few VARCHAR lengths. I've seen plenty of production tables running fine with a mix of VARCHAR and TEXT columns after this change. You've got this.

Related Errors in Database Errors
0X40000004 STATUS_RXACT_STATE_CREATED (0X40000004) – What It Means and How to Fix ERROR 1062: Duplicate entry 'xxx' for key 'PRIMARY' Duplicate Entry for Key Primary on Insert – Quick Fixes SQLSTATE[HY000] [2002] Connection refused Laravel DB Timeout: Quick Fixes That Actually Work 1064 MariaDB 1064: syntax error near WHERE clause on UPDATE

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.