Halim's avatar

Migration fails with "Specified key was too long; max key length is 1000 bytes" on MySQL 8.4.7

Hi, I am getting the following error when running php artisan migrate on a fresh Laravel 13 installation:

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes — table failed_jobs add index failed_jobs_connection_queue_failed_at_index(connection, queue, failed_at)

Environment:

Laravel 13.16.1

PHP 8.3

MySQL 8.4.7

WAMP on Windows

What I already tried:

Added Schema::defaultStringLength(191) in AppServiceProvider::boot()

Updated the migration file to use string('queue', 191), string('uuid', 191), and string('id', 191)

Removed the composite index $table->index(['connection', 'queue', 'failed_at']) from the failed_jobs table

Ran php artisan config:clear and php artisan cache:clear before each attempt

Dropped all tables and re-ran php artisan migrate:fresh

None of the above fixed the issue. The error persists on the create_jobs_table migration. Is this a known issue with Laravel 13 and MySQL 8.4? Any help is appreciated.

0 likes
5 replies
LaryAI's avatar
Level 58

Certainly! This is a common issue that can happen even on MySQL 8+ (including 8.4.x) and recent Laravel versions. The root cause is almost always related to character set and collation, index length limits, or an overlooked configuration. Here are steps to fully resolve the problem:


1. Check the Default String Length

You already set:

Schema::defaultStringLength(191);

But Unicode collations can still exceed index sizes depending on the DB config.


2. Set a Compatible Charset and Collation

Make sure your application and database are using a charset/collation that allows reasonable index lengths (ideally utf8mb4 with utf8mb4_unicode_ci).

In your .env file:

DB_CONNECTION=mysql
DB_DATABASE=your_database
DB_USERNAME=your_user
DB_PASSWORD=your_password

DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci

In your config/database.php:

'mysql' => [
    // ...
    'charset' => env('DB_CHARSET', 'utf8mb4'),
    'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
    // ...
],

3. Check the Storage Engine

Make sure you're not using anything except InnoDB. MyISAM still has a 1000-byte index key length limit per key. MySQL 8+ should use InnoDB by default, but double-check with:

SHOW TABLE STATUS WHERE Name = 'failed_jobs';

If not, set it in your migration:

$table->engine = 'InnoDB';

4. Recreate the Database with the Right Defaults (Optional but recommended)

If possible, recreate your development database entirely with the proper charset/collation so new tables inherit the right settings:

CREATE DATABASE your_database CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

5. Clear All Caches and Config, Then Retry

php artisan config:clear
php artisan cache:clear
php artisan migrate:fresh

Example Migration Fix

Here’s what your migration should look like:

public function up()
{
    Schema::create('failed_jobs', function (Blueprint $table) {
        $table->id();
        $table->string('uuid')->unique();
        $table->text('connection');
        $table->text('queue');
        $table->longText('payload');
        $table->longText('exception');
        $table->timestamp('failed_at')->useCurrent();
        $table->index(['connection', 'queue', 'failed_at']);
        $table->engine = 'InnoDB'; // Force InnoDB
    });
}

Note: If your connection or queue fields are set as text (not string), MySQL won’t be able to index them, so define proper lengths:

$table->string('connection', 100);
$table->string('queue', 100);

Or if you need to keep them as text due to large values, remove the index or make them string(191).


Why is This Happening Even On MySQL 8?

  • If your DB/table/column uses utf8mb4 (4 bytes/char) and you have 3 string columns each 191 chars, that's 3*191*4 = 2292 bytes, exceeding the MySQL limit for index length per index.
  • Even InnoDB (MySQL 8+) restricts index bytes per key for some settings.

Summary Checklist

  • Set utf8mb4 and utf8mb4_unicode_ci in both .env and database.php.
  • Make sure your migration uses correct string lengths (string('field', 191)).
  • Use InnoDB, not MyISAM.
  • Recreate DB if possible.
  • Clear caches and rerun.

References


If you follow these steps, the error will be resolved. If not, paste your full migration and config/database.php, and I can look further.

JussiMannisto's avatar

The issue isn't with Laravel, it's your database. MySQL uses the InnoDB storage engine, which at one point had a 1000 byte size limit for its keys by default. It looks like your database has some old configuration.

Laravel's MySQL config uses the utf8mb4 encoding by default, where each character takes 4 bytes. Even if you shortened all string columns to 191 characters, the composite key size would exceed its limit.*

You can fix the problem by updating your MySQL config. Add or update these values in my.ini, then restart the database service and run migrate:fresh:

innodb_default_row_format = dynamic
innodb_file_per_table = 1

These are the modern defaults that remove the limitation. You can read what they do from the database docs.

* Although I must say, Laravel's defaults are pretty bad. 255 characters for an indexed UUID column? Why?

Tray2's avatar

I would even go so far as to why UUID at all if you don't need to make it impossible to guess.

JussiMannisto's avatar

That's because the job ID is generated in code, not by a database. The job needs a unique ID before it's pushed to a queue worker.

Glukinho's avatar

Removed the composite index $table->index(['connection', 'queue', 'failed_at']) from the failed_jobs table

This is strange. Removing this should bypass the error without much harm:

// database/migrations/0001_01_01_000002_create_jobs_table.php

Schema::create('failed_jobs', function (Blueprint $table) {
    // ...
    $table->index(['connection', 'queue', 'failed_at']); // <== remove this line
});

Are you sure of that?

Please or to participate in this conversation.