应修改 appserviceprovider::boot() 中索引命名逻辑并设置字符串长度:先调用 schema::defaultstringlength(191),再用 builder::setindexnamegenerator() 限制索引名总长≤56字符,迁移中显式指定短索引名。

MySQL 5.7 及更早版本报 SQLSTATE[42000]: Syntax error or access violation 怎么办
根本不是语法写错了,是 Laravel 自动生成的索引名超长(比如 users_email_verified_at_index 拼上表前缀后轻松突破 64 字符),而 MySQL 5.7 默认关着 innodb_large_prefix,硬性限制索引名长度。别去改数据库配置——很多阿里云 RDS 或共享主机根本不让你开。
真正可控的解法,是在 App\Providers\AppServiceProvider::boot() 里接管索引命名逻辑:
- 必须先调用
Schema::defaultStringLength(191),否则后续索引创建会因字段长度问题二次报错 - 用
Builder::setIndexNameGenerator()替换默认生成器,核心是控制总长 ≤ 48 字符 + 8 字符哈希(避免冲突) - 回调函数中别直接拼
$column,它可能含下划线或长字段名,优先用$table和$type构建主干 - PHP 8.0+ 可用
md5($table . $column . $type)[0, 8];低版本请改用substr(md5(...), 0, 8)
迁移文件里手动指定索引名比依赖自动命名更稳
自动命名省事但不可控,尤其当表名本身很长(如 tenant_organization_user_permissions)或字段带双下划线时,再短的策略也容易撞上限。显式命名才是生产环境该用的方式。
- 单字段索引:
$table->index('email', 'idx_users_email') - 联合索引:
$table->index(['user_id', 'status'], 'idx_user_status') - 删除时必须用相同名称:
$table->dropIndex('idx_users_email'),别用dropUnique()这类方法——它们内部仍会拼名,照样超长 - 第三方包(如
spatie/laravel-permission)发布的迁移也适用此法,发布后可直接编辑迁移文件补上名称
php artisan migrate:fresh 为什么会执行框架自带的迁移并报索引错
因为 migrate:fresh 不区分“谁写的迁移”,它扫描 database/migrations/ 下所有 YYYY_MM_DD_HHIISS_*.php 文件,包括 Laravel 自动发布的(如 2019_12_14_000001_create_personal_access_tokens_table.php)或权限包发布的迁移。这些迁移里常有联合索引(如 (tokenable_type, tokenable_id)),在旧 MySQL 上极易触发 Specified key was too long。
- 这类迁移不会因为你没手动创建就跳过,只要在目录里、格式对,就会被执行
- 报错位置往往不是你写的迁移,而是框架或包的迁移,容易误判
- 解决路径唯一:要么提前在
AppServiceProvider注册短名生成器,要么进对应迁移文件把->unique()改成带名的->unique('idx_tokens_type_id') - 不要删迁移文件来“绕过”,否则下次
vendor:publish可能重新拉进来
为什么改了 AppServiceProvider 还是报错
常见原因是注册时机不对,或者缓存没清。Laravel 的命名策略只在迁移开始前注册才生效,已加载的迁移类不会重新解析。
- 确保
setIndexNameGenerator()写在boot()方法最开头,且没有条件判断包裹 - 执行
php artisan config:clear和php artisan cache:clear,否则旧配置可能被缓存住 - 如果之前迁移已失败,
migrations表可能残留脏数据,建议先php artisan migrate:reset --force再重试 - 验证是否生效:临时在生成器回调里加
dd($table, $column, $type),看是否被调用
defaultStringLength(191))是两套机制,但必须同时生效。漏掉任何一个,都可能在不同环节卡住——前者防索引名超长,后者防字段内容超字节限制。这两个动作缺一不可,且必须在第一次运行迁移前就位。











