ERROR 1146 (42S02): Table 'database.table_name' doesn't exist is raised when MySQL cannot find a table in the data dictionary. The table either has never been created, was dropped, or the query references the wrong database or a misspelled name.
Impact
Any query (SELECT, INSERT, UPDATE, DELETE) or DDL (ALTER TABLE, DROP TABLE) targeting a non-existent table fails immediately. In application code this usually surfaces as an unhandled exception. In migration scripts, it halts the migration.
Common Causes
- Wrong database selected: the session is in a different database than expected,
USE wrong_dbwas called, or no database was selected - Table was never created: a migration did not run, or the
CREATE TABLEwas skipped by an error - Case sensitivity mismatch: on Linux (case-sensitive filesystem),
usersandUsersare different tables;lower_case_table_namessetting controls this - Table was accidentally dropped and the application still references it
lower_case_table_namesmismatch between development (macOS, case-insensitive) and production (Linux, case-sensitive)- InnoDB data dictionary inconsistency: the
.ibdfile exists but the data dictionary entry does not, or vice versa (after a crash or improper restore) - Using the wrong connection string or environment variable pointing to a different database
- Partitioned table partition missing: the table header exists but a partition's data file is gone
- View referencing a base table that was dropped
Troubleshooting and Resolution Steps
Verify which database the session is using:
SELECT DATABASE(); SHOW DATABASES; USE mydb;Check whether the table exists in any database:
SELECT table_schema, table_name, engine, create_time FROM information_schema.tables WHERE table_name = 'orders' ORDER BY table_schema;If it appears in a different schema, your query is using the wrong database context.
List all tables in the current database:
SHOW TABLES; SHOW TABLES LIKE '%order%';Check for case-sensitivity issues:
SHOW VARIABLES LIKE 'lower_case_table_names';0= names stored as given, comparisons case-sensitive (Linux default)1= names stored lowercase, comparisons case-insensitive (Windows default)2= names stored as given, comparisons case-insensitive (macOS default)
If
lower_case_table_names=0(Linux production) and the table was created asOrdersbut the query usesorders, MySQL cannot find it:-- Table created as: CREATE TABLE Orders (...); -- Query fails on case-sensitive systems: SELECT * FROM orders; -- 1146 on Linux -- Fix: use the exact case SELECT * FROM Orders; -- Long-term fix: rename table to lowercase RENAME TABLE Orders TO orders;Re-run migrations if the table was never created:
# Check migration status (Flyway example) flyway info # Re-run pending migrations flyway migrateIn Django:
python manage.py showmigrations python manage.py migrateRecreate a dropped table from your schema definition. If you have version-controlled migrations, replay from the last known-good backup:
-- Check the binary log for the DROP statement mysqlbinlog /var/log/mysql/mysql-bin.000123 | grep -A5 -i "DROP TABLE" -- Restore from backup if neededFix an InnoDB data dictionary inconsistency (
.ibdfile exists but table not in dictionary, or vice versa). First check:# Does the .ibd file exist on disk? ls -la /var/lib/mysql/mydb/orders.ibd-- Does the table appear in information_schema? SELECT * FROM information_schema.tables WHERE table_name = 'orders'; -- If .ibd exists but table is not in dictionary, import the tablespace: CREATE TABLE orders (...) ENGINE=InnoDB; -- create with the original DDL ALTER TABLE orders DISCARD TABLESPACE; -- Copy the .ibd file to the data directory ALTER TABLE orders IMPORT TABLESPACE;Fix a view that references a dropped table:
-- Find views with broken references SELECT table_schema, table_name, view_definition FROM information_schema.views WHERE table_schema = 'mydb'; -- Drop and recreate the view, or fix the underlying table reference DROP VIEW IF EXISTS customer_summary; CREATE VIEW customer_summary AS SELECT ...; -- using the correct tableQualify table names with the schema in queries to avoid relying on the session's current database:
-- Explicit schema qualification, always works regardless of USE SELECT * FROM mydb.orders WHERE id = 1;
Additional Information
lower_case_table_namesmust be set consistently across all MySQL instances in a replication topology. Changing it on a running server that already has data requires exporting all data, setting the variable, and reimporting. It cannot be changed online on MySQL 8.0 after initialization.- On macOS with the default
lower_case_table_names=2, code that works locally may fail in production on Linux (lower_case_table_names=0) if table names differ in case. Enforce lowercase table names in migrations to prevent this. - InnoDB stores each table's data in
datadir/db_name/table_name.ibd(withinnodb_file_per_table=ON). If a.ibdfile is deleted outside of MySQL (e.g., by mistake withrm), the table appears ininformation_schemabut all queries against it fail with error 1146 or a different InnoDB-level error.
Frequently Asked Questions
Q: The table exists in information_schema.tables but queries return error 1146. How?
A: This is an InnoDB data dictionary inconsistency. The metadata exists but the physical tablespace file (.ibd) is missing or corrupt. Use SHOW TABLE STATUS LIKE 'tablename'\G, it will show an error for the engine if the file is missing. Restore from backup.
Q: After restoring a backup, some tables return error 1146. Why?
A: If the backup was taken as a physical copy (file copy) without InnoDB being in a consistent state, the data dictionary may be out of sync with the .ibd files. Always use mysqldump (logical backup), xtrabackup --prepare, or take a snapshot only after MySQL is stopped or while using mysqldump --single-transaction.
Q: My ORM generates table names differently depending on the environment. How do I standardize?
A: Explicitly set the db_table Meta option (Django), __tablename__ (SQLAlchemy), or equivalent in your ORM to a lowercase explicit string, not a derived class name. Relying on class name → table name inference can produce different names on different platforms.
Q: Can I get a list of all missing tables (referenced in views or FKs but not existing)? A: For foreign keys:
SELECT referenced_table_schema, referenced_table_name
FROM information_schema.referential_constraints
WHERE referenced_table_name NOT IN (
SELECT table_name FROM information_schema.tables
WHERE table_schema = referenced_table_schema
);
For views: inspect VIEW_DEFINITION in information_schema.views and parse referenced table names.