MySQL: "Foreign key constraint is incorrectly formed"

Ah, MySQL, source of many weird and incomprehensible error messages. Like this one:

Error 150: Foreign key constraint is incorrectly formed

There are a number of possible reasons for this error. A lot of them are described on Stackoverflow, but there is one missing and I wanted to collect the reasons in one place, so here they are.

Debugging

If you encounter this error, consider running SHOW ENGINE INNODB STATUS status immediately after the failed FK query. The InnoDB status usually contains all the information you need to fix the issue. An example output could look like this:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
Error in foreign key constraint creation for table `mytable`.`#sql-6a70_2`.
A foreign key constraint of name `mytable`.`my-fk`
already exists. (Note that internally InnoDB adds 'databasename'
in front of the user-defined constraint name.)
Note that InnoDB's FOREIGN KEY system tables store
constraint names as case-insensitive, with the
MySQL standard latin1_swedish_ci collation. If you
create tables or databases whose names differ only in
the character case, then collisions in constraint
names can occur. Workaround: name your constraints
explicitly with unique names.

Reason 1: Column types don’t match

This is the most obvious reason. If you try to create a foreign key from an INT(10) column to a SMALLINT(5) column, you will get the error above.

Simply make sure that the column types are identical, including a possible UNSIGNED flag.

Reason 2: MyISAM instead of InnoDB

MyISAM does not support foreign keys. It’s as easy as that. Use InnoDB or any other storage engine that can handle FKs. But be aware that InnoDB is no silver bullet and you might have tables which work better in simpler engines like MyISAM (especially if you fear your InnoDB log growing indefinitely for something like log tables).

Reason 3: Foreign Key name not unique

Believe it or not, but the names of foreign keys must be unique within the same database. Depending on your MySQL version, you might also get the

Can’t create table ‘mydatabase.#sql-798_ffe95d’ (errno: 121) Duplicate key on write or update

error message.

Reason 4: Impossible ON DELETE or ON UPDATE clauses

You cannot create a foreign key with ON UPDATE SET NULL if the column does not allow NULL values. Sounds obvious, but I tripped over that after checking that in fact, the columns in both tables are identical.

Conclusion

MySQL’s error messages are a mess. Thankfully, SHOW ENGINE INNODB STATUS can help if one doesn’t spot the problem right away.