外键字段类型必须与被引用主键完全一致,laravel 11 中报错 errno: 150 通常因 signed/unsigned 或 int/bigint 不匹配;须用 foreignid() 自动适配类型并显式指定约束名,且被引用表迁移必须先于引用表执行。

外键字段类型必须与被引用主键完全一致
在 Laravel 11 中执行迁移时若报错 General error: 1005 Can't create table ... (errno: 150 "Foreign key constraint is incorrectly formed"),几乎一定是外键列与目标主键列的数据类型不匹配。
比如你用 $table->id() 创建了 users 表,其 id 实际是 unsignedBigInteger;但你在 posts 表中写了 $table->integer('user_id'),这就导致符号性(signed vs unsigned)、位宽(INT vs BIGINT)全部错配。
必须改用 foreignId('user_id'),它会自动适配目标表主键类型,且默认添加索引——这是 Laravel 9+ 起强制推荐的写法,不是可选项。
如果目标表主键不是 id(例如 $table->id('user_no')),则需显式指定:foreignId('user_id')->constrained('users', 'user_no')。
外键约束名必须手动指定
MySQL 和 PostgreSQL 对外键约束名的自动生成规则完全不同,Laravel 默认不设名会导致迁移回滚失败、重命名报错、多人协作时约束名冲突。
方法一:使用 foreignId() 链式调用 ->name()
$table->foreignId('user_id')->constrained()->onDelete('cascade')->name('fk_posts_user_id_users');
方法二:用 unsignedBigInteger() + foreign() 组合,但必须在 foreign() 后立刻加 ->name()
$table->unsignedBigInteger('user_id');<br>$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->name('fk_posts_user_id_users');
注意:不能只写 unsignedBigInteger('user_id') 然后另起一行调用 foreign() —— 这样链式中断,->name() 无法绑定到该约束上。
确保被引用表先于引用表创建
第一步:确认迁移文件时间戳顺序是否合理。Laravel 按文件名前缀的时间戳升序执行迁移,若 posts 表迁移时间戳早于 users 表,外键就必然失败。
第二步:检查两个迁移文件名,例如:
2026_03_15_102030_create_users_table.php2026_03_14_091520_create_posts_table.php
这里 posts 迁移时间戳更早,但又依赖 users 表,必须重命名该文件,把时间戳改为 2026_03_15_102031 或之后。
第三步:删除已失败的迁移记录(如有)并重新运行:php artisan migrate:fresh 或先 php artisan migrate:rollback --step=1 再 php artisan migrate。











