Fixing MySQL ERROR 1242 (21000): Subquery returns more than 1 row

intermediate🗄️ MySQL2026-07-18| MySQL 5.7, MySQL 8.0+, MariaDB (Ubuntu, CentOS, Windows, macOS)

Error Message

ERROR 1242 (21000): Subquery returns more than 1 row
#mysql#database#sql-optimization#troubleshooting

The Error Message

You are likely running a complex report or updating records when MySQL suddenly stops. The terminal or application logs will display this specific message:

ERROR 1242 (21000): Subquery returns more than 1 row

Why This Happens

At its core, this is a logic mismatch. MySQL expects a scalar value—a single piece of data like the number 5 or the string 'Active'—but your subquery is handing over a list. This usually happens in three specific scenarios:

  • You used a comparison operator (=, <, >) that only works with one value.
  • A subquery is placed inside a SELECT list to create a single column.
  • The subquery acts as an argument for a function that doesn't support arrays or sets.

If your database logic assumes a user only has one active subscription, but the data actually contains three, the query will break immediately.

Step-by-Step Fixes

Method 1: Use the LIMIT 1 Clause

When you only need the most recent record or a single representative value, LIMIT 1 is the most direct solution. It forces the subquery to stop after finding its first match, satisfying the scalar requirement.

Example of a failing query:

SELECT name, 
       (SELECT order_date FROM orders WHERE orders.user_id = users.id) as last_order
FROM users;

If user #402 has placed 12 orders, the subquery returns 12 dates, and the query crashes. The fix:

SELECT name, 
       (SELECT order_date FROM orders 
        WHERE orders.user_id = users.id 
        ORDER BY order_date DESC LIMIT 1) as last_order
FROM users;

Method 2: Switch from = to IN

The equals operator (=) is strict; it demands a single match. If your subquery might return a collection of IDs, swap the equals sign for the IN operator. IN is designed specifically to handle lists of values.

Example of a failing query:

SELECT * FROM products 
WHERE category_id = (SELECT id FROM categories WHERE name = 'Electronics');

If your store has 'Electronics' categories for both 'Retail' and 'Wholesale' (IDs 5 and 12), the subquery returns both. The fix:

SELECT * FROM products 
WHERE category_id IN (SELECT id FROM categories WHERE name = 'Electronics');

Method 3: Use Aggregate Functions

Sometimes you don't want a random row; you want a summary. Aggregate functions like MAX(), MIN(), or SUM() naturally compress multiple rows into a single scalar value. This is ideal for financial or chronological data.

Example of a failing query:

UPDATE employees 
SET salary = (SELECT amount FROM bonuses WHERE employee_id = 101)
WHERE id = 101;

If employee 101 received three different bonuses this month, the update fails. The fix (using SUM):

UPDATE employees 
SET salary = salary + (SELECT SUM(amount) FROM bonuses WHERE employee_id = 101)
WHERE id = 101;

Method 4: Use EXISTS for Presence Checks

If you are only checking if a related record exists, avoid subquery comparisons entirely. Use EXISTS instead. It is more performant because it stops searching as soon as it finds a single match. It also bypasses row count errors because it returns a boolean (true/false) rather than data.

Example of a failing query:

SELECT * FROM articles 
WHERE id = (SELECT article_id FROM comments WHERE status = 'pending');

The fix:

SELECT * FROM articles a 
WHERE EXISTS (SELECT 1 FROM comments c WHERE c.article_id = a.id AND c.status = 'pending');

Method 5: Audit for Duplicate Data

Sometimes the SQL is perfect, but the data is messy. If a table that should be unique (like user_profiles) contains two rows for the same user_id, Error 1242 will surface. This is often a sign of a missing database constraint.

Search for duplicates using this pattern:

SELECT user_id, COUNT(*) 
FROM profiles 
GROUP BY user_id 
HAVING COUNT(*) > 1;

After cleaning the duplicates, apply a UNIQUE constraint to the column to prevent the error from returning in the future.

Verification

Test your fix in a safe environment like MySQL Workbench or TablePlus before deploying. Check these three points:

  • Confirm the error message is gone.
  • Verify the row count. Using IN can sometimes return more rows than you intended if the subquery is too broad.
  • Double-check your ORDER BY logic if you used LIMIT 1. Ensure you are getting the "newest" or "cheapest" record rather than just a random one.

Pro Tips for Prevention

  • Default to LIMIT 1: In scalar subqueries, adding LIMIT 1 acts as a safety net against unexpected data growth.
  • Choose JOINs: Whenever possible, use a LEFT JOIN or INNER JOIN. They are generally faster and much easier to debug than nested subqueries.
  • Enforce Uniqueness: Use UNIQUE indexes on columns that represent one-to-one relationships. This stops the error at the source—the data entry point.
  • Scale Testing: A query that works with 5 rows of test data might break with 50,000 rows of production data. Always test with realistic datasets.

Related Error Notes