laravel迁移报错1071是因utf8mb4下255字符索引超mysql 767字节限制,解决方案是在appserviceprovider的boot方法中设置schema::defaultstringlength(191),确保191×4=764字节不超限。

直接改 Schema::defaultStringLength(191) 就能过,但得先确认 MySQL 版本和字符集是否真支持 utf8mb4 —— 否则只是把报错压到建索引那一刻。
为什么 Specified key was too long 总在 php artisan migrate 时出现
这不是 Laravel 的 bug,是 MySQL 对索引键长度的硬限制(比如旧版 InnoDB 是 767 字节)。Laravel 5.4+ 默认用 utf8mb4,一个字符最多占 4 字节;string('email') 默认建 255 字符字段,255 × 4 = 1020 字节,远超 767。加上唯一索引、主键索引一建,立刻触发 1071 错误。
常见报错语句长这样:SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes。
- 只在加索引时爆(如
->unique()、->index()),字段本身创建可能成功 - 哪怕表已存在,后续迁移里新增带索引的
string字段也会中招 - MySQL 5.7.7+ +
innodb_large_prefix=ON可放宽到 3072 字节,但默认不开启
怎么配 Schema::defaultStringLength() 才不翻车
在 app/Providers/AppServiceProvider.php 的 boot() 方法里写这行:
Schema::defaultStringLength(191);
191 是关键数字:191 × 4 = 764 字节,刚好卡在 767 限制内,留了 3 字节余量。
- 别写 192 —— 192 × 4 = 768,超限
- 别在
register()里调,必须在boot()中,否则迁移命令不生效 - 如果项目已上线且有历史迁移,改完要重跑
php artisan migrate:fresh或手动删表再迁(开发环境) - 该配置只影响新迁移文件里未显式指定长度的
string(),已写死string('name', 255)的不受影响
MySQL 版本和配置不达标,光改 PHP 没用
如果 MySQL 是 5.5.x 或 5.6.x,即使写了 Schema::defaultStringLength(191),某些场景下仍可能失败 —— 因为老版本不支持 utf8mb4 索引前缀压缩。
- 查版本:
SELECT VERSION(); - 确认字符集:
SHOW VARIABLES LIKE 'character_set_database';和SHOW VARIABLES LIKE 'collation_database';,必须是utf8mb4相关 - 检查
innodb_large_prefix:SHOW VARIABLES LIKE 'innodb_large_prefix';,MySQL 5.7.7+ 默认 ON,旧版需手动开(并设innodb_file_format=Barracuda、innodb_file_per_table=ON) - 如果实在不能升级 MySQL,临时方案是降级字符集:在
config/database.php的 mysql 配置里加'charset' => 'utf8', 'collation' => 'utf8_unicode_ci',但会丢 Emoji 支持
线上改字段长度时,defaultStringLength 不起作用
这个配置只管新字段的默认长度,不管已有字段的变更。比如你线上已有 users.name 是 VARCHAR(100),现在想扩到 255,必须走新迁移文件 + change(),而不是靠它自动适配。
- 扩字段长度必须新建迁移:
php artisan make:migration extend_users_name_length - 在
up()里写:$table->string('name', 255)->change(); - 确保已
use Illuminate\Support\Facades\Schema;,且数据库支持MODIFY COLUMN(MySQL 5.7.5+ 更稳) - 如果字段已有超长数据(比如存了 200 字符的字符串),
change()会直接失败,得先清理或截断数据
最易被忽略的一点:这个配置对 php artisan migrate:rollback 无效 —— 回滚时用的是原始迁移文件里的定义,所以千万别在已提交的迁移里改 string() 长度,否则 rollback 再 migrate 就会冲突。











