ERROR 1066 (42000): Not unique table/alias: '<name>' is raised when a query's FROM clause (or JOIN chain) references the same table name or alias more than once and MySQL cannot distinguish between the two references. The error symbol is ER_NONUNIQ_TABLE.
Impact
The query is rejected immediately — no rows are read or modified. Because MySQL cannot determine which instance of the table a column reference belongs to, it refuses to parse the statement rather than return ambiguous results. The error appears at parse time, so it never touches any transaction state and there is no rollback needed.
Developers most often hit this when writing self-joins, copying a JOIN clause by mistake, or when an ORM generates a query that joins the same table twice for two different associations. Frameworks like Hibernate, ActiveRecord, or SQLAlchemy can produce duplicate table references when eager-loading multiple relations that share an intermediate table, so the error may surface as a runtime exception in application logs rather than during local development.
Common Causes
- Self-join without aliases — Joining a table to itself without assigning distinct aliases to each reference. MySQL requires unique identifiers for every table instance in a
FROMorJOINclause. - Duplicate table in FROM clause — Listing the same table twice in a comma-separated
FROMclause or adding it both explicitly and via aJOIN. - Subquery alias collision — Using the same alias for a derived table or subquery as for a base table already referenced in the outer query.
- ORM or query-builder generating duplicate joins — Two relationships defined on the same model both resolve to the same table, and the query builder adds it twice without generating unique aliases.
- Copy-paste error in complex queries — Duplicating a
LEFT JOINblock while editing a multi-join query and forgetting to remove or rename the copy.
Troubleshooting and Resolution Steps
Identify the duplicate name in the error message. MySQL tells you the exact name or alias that is duplicated. Locate every occurrence of that identifier in your
FROMandJOINclauses.Add distinct aliases to a self-join. Every instance of the table must have a unique alias:
-- Broken: same table referenced twice with no alias SELECT a.id, b.manager_id FROM employees, employees WHERE employees.manager_id = employees.id; -- Fixed: assign a unique alias to each instance SELECT e.id, m.id AS manager_id FROM employees AS e JOIN employees AS m ON e.manager_id = m.id;Remove the accidental duplicate join. If the same table appears more than once but you only need it once, delete the extra
JOINorFROMentry:-- Broken: orders joined twice SELECT o.id, c.name FROM orders o JOIN customers c ON o.customer_id = c.id JOIN orders o ON o.status = 'pending'; -- duplicate -- Fixed: apply the extra condition to the existing join or a WHERE clause SELECT o.id, c.name FROM orders o JOIN customers c ON o.customer_id = c.id WHERE o.status = 'pending';Alias subqueries so they do not collide with base tables. A derived table alias must differ from every other table alias in the same query scope:
-- Broken: derived table shares the name 'orders' SELECT * FROM orders JOIN (SELECT customer_id FROM orders WHERE total > 100) AS orders ON orders.customer_id = orders.customer_id; -- Fixed: use a distinct alias for the subquery SELECT o.* FROM orders o JOIN (SELECT customer_id FROM orders WHERE total > 100) AS big_orders ON o.customer_id = big_orders.customer_id;Inspect ORM-generated SQL. Enable query logging or use your framework's debug/explain mode to see the raw SQL. For example, in MySQL you can enable the general log temporarily:
SET GLOBAL general_log = 'ON'; SET GLOBAL general_log_file = '/tmp/mysql_general.log';Once you find the duplicate join in the generated SQL, fix it at the ORM layer by specifying explicit join conditions or using a single association instead of two that resolve to the same table.
Additional Information
- The SQLSTATE code is
42000(Syntax Error or Access Rule Violation), which means the error is treated as a syntax/parse problem, not a data error. - Error 1066 is purely a query-construction issue and does not depend on MySQL's
sql_modesettings — it is raised in all modes. - The error applies equally to
SELECT,UPDATEwith multi-table syntax, andDELETEwith multi-table syntax. Multi-tableUPDATEandDELETEstatements are particularly prone to duplicate table references because the updated table often appears in both the target list and theFROM/JOINclause — MySQL handles that specific pattern, but any other duplication still raises 1066. - Related error:
ERROR 1052 (23000): Column '<col>' in <clause> is ambiguous— this is a different error raised when column names are ambiguous across multiple tables, whereas 1066 is about the table/alias names themselves being non-unique.
Frequently Asked Questions
Why does MySQL require unique table aliases at all?
MySQL's query planner needs an unambiguous way to refer to each row source in a query. If two references share the same name, column references like tablename.column become undefined because MySQL cannot know which instance you mean. Requiring unique names at parse time prevents silently wrong results.
Can I join the same table more than once in a single query?
Yes, but every instance must have a distinct alias. This is standard SQL and is commonly used for self-joins, or when joining a lookup/reference table for two different foreign keys in the same row. Just ensure each JOIN clause uses a different alias (AS a, AS b, etc.).
The error appears in my application but I cannot see the SQL. How do I find it?
Enable the MySQL general query log (SET GLOBAL general_log = 'ON') or, in a development environment, configure your ORM to log SQL statements. In Django use django.db.backends logging; in Rails set config.log_level = :debug; in Spring Boot set logging.level.org.hibernate.SQL=DEBUG. The raw SQL will contain the duplicate table name.
Does this error occur with CTEs (Common Table Expressions)?
A CTE name must also be unique within the WITH clause, but CTEs use a different error path. If you reference the same CTE name twice in the main query you will still get error 1066, because the CTE name acts as a table alias in the main FROM/JOIN scope.