How to Fix MySQL Error 1415: Not Allowed to Return a Result Set from a Trigger

ERROR 1415 (0A000): Not allowed to return a result set from a trigger is raised when a trigger body executes a SELECT statement that would return rows directly to the client. The error symbol is ER_SP_NO_RETSET.

Impact

MySQL triggers execute automatically in response to INSERT, UPDATE, or DELETE events on a table. Unlike stored procedures, triggers are not invoked by client code that expects a result set — they fire as side effects within the statement that triggered them. Because of this, MySQL forbids any statement inside a trigger that would send rows back to the client connection.

When this error is raised, the triggering DML statement (INSERT, UPDATE, or DELETE) is aborted and rolled back. Any application that relies on that statement — an ORM performing a model save, a migration script inserting seed data, or an API endpoint updating a record — will receive this error and fail. The error surfaces at the moment the trigger fires, not at trigger creation time, so a problematic trigger can be deployed undetected and only fail when rows are actually modified.

Common Causes

  1. A bare SELECT inside a trigger body. A developer writes a SELECT ... FROM some_table WHERE ... directly in the trigger to look up a related value, not realizing that unassigned SELECT statements in a trigger context send rows to the client.

  2. Calling a stored procedure from a trigger that itself contains a result-returning SELECT. If the trigger calls CALL my_proc() and my_proc has an unassigned SELECT, the rows propagate through the procedure call and violate the trigger restriction.

  3. Debugging SELECT left in trigger code. A developer adds a SELECT 'reached this point' or SELECT NEW.id for debugging, then forgets to remove it before deploying.

  4. Using SELECT ... INTO incorrectly. Forgetting the INTO clause when assigning a value to a variable, turning what should be a variable assignment into a result-returning query.

Troubleshooting and Resolution Steps

  1. Inspect the trigger body to find the offending SELECT:

    SHOW CREATE TRIGGER trigger_name\G
    

    Or query the information schema across all triggers on a table:

    SELECT TRIGGER_NAME, ACTION_STATEMENT
    FROM information_schema.TRIGGERS
    WHERE EVENT_OBJECT_SCHEMA = 'your_db'
      AND EVENT_OBJECT_TABLE  = 'your_table';
    
  2. Replace bare SELECT with SELECT ... INTO when reading a value into a variable. This is the most common fix — the result is captured in a variable instead of being returned to the client:

    -- Wrong: returns a result set
    CREATE TRIGGER after_order_insert
    AFTER INSERT ON orders
    FOR EACH ROW
    BEGIN
      SELECT discount_rate FROM pricing WHERE tier = NEW.tier;  -- ERROR 1415
    END;
    
    -- Correct: assign the value into a local variable
    CREATE TRIGGER after_order_insert
    AFTER INSERT ON orders
    FOR EACH ROW
    BEGIN
      DECLARE v_discount DECIMAL(5,2);
      SELECT discount_rate INTO v_discount
      FROM pricing
      WHERE tier = NEW.tier;
      -- use v_discount for further logic
    END;
    
  3. Remove debugging SELECT statements from the trigger body. Replace any SELECT 'debug message' lines with a no-op or delete them entirely, then recreate the trigger:

    DROP TRIGGER IF EXISTS trigger_name;
    -- recreate without the SELECT statement
    
  4. Fix stored procedures called from the trigger. If the trigger calls a stored procedure, audit that procedure for unassigned SELECT statements:

    SHOW CREATE PROCEDURE procedure_name\G
    

    Rewrite any result-returning SELECT inside the procedure to use SELECT ... INTO variables, or restructure so the procedure does not return result sets when called from a trigger context.

  5. Re-create the trigger after applying fixes. MySQL stores trigger definitions as-is, so ALTER TRIGGER does not exist — you must drop and recreate:

    DROP TRIGGER IF EXISTS after_order_insert;
    
    DELIMITER $$
    CREATE TRIGGER after_order_insert
    AFTER INSERT ON orders
    FOR EACH ROW
    BEGIN
      DECLARE v_discount DECIMAL(5,2);
      SELECT discount_rate INTO v_discount
      FROM pricing
      WHERE tier = NEW.tier;
    END$$
    DELIMITER ;
    

Additional Information

  • The SQLSTATE 0A000 is the standard "feature not supported" class, indicating this is a categorical restriction in MySQL's execution model, not a configuration issue.
  • The same restriction applies to events (CREATE EVENT) — a scheduled event body cannot contain a bare SELECT that returns rows to a client either.
  • SELECT ... INTO @user_variable (session variables) is also valid inside a trigger and avoids the error, in addition to SELECT ... INTO local_variable.
  • Stored procedures do not have this restriction by default — a CALL from a client connection can return result sets from a procedure. The restriction is specific to triggers (and events) because they have no direct client caller to receive rows.
  • ORMs such as Hibernate, SQLAlchemy, and ActiveRecord typically surface this as a generic database execution error wrapping ERROR 1415. Check the caused-by chain in the exception for the MySQL error code.
  • There is no MySQL configuration option to lift this restriction — it is inherent to the trigger execution model in all MySQL versions (5.x, 8.0, 8.4).

Frequently Asked Questions

Why can stored procedures return result sets but triggers cannot? A stored procedure is called explicitly by a client (CALL proc()), so MySQL knows there is a client waiting to receive rows. A trigger fires implicitly as part of another statement — there is no separate client call context expecting rows from the trigger, so returning a result set is undefined and therefore prohibited.

Can I use SELECT ... INTO freely inside a trigger? Yes. SELECT col INTO var FROM t WHERE ... assigns the result to a local declared variable or a session variable (@var) and does not send rows to the client. This is the standard way to read data inside a trigger and is fully supported.

The trigger was created without error, so why does MySQL only fail at runtime? MySQL does not fully validate trigger bodies against all runtime restrictions at CREATE TRIGGER time. The check that a result set cannot be returned is enforced at execution time, when the trigger actually fires. This means the trigger can be created and deployed successfully, and the error only appears when a matching INSERT/UPDATE/DELETE occurs.

Can I call a stored procedure from a trigger if that procedure conditionally returns rows? No. If the procedure contains any code path that could return a result set, and that path is taken at runtime, MySQL will raise error 1415. The safest approach is to ensure procedures that are called from triggers never contain bare SELECT statements — use SELECT ... INTO exclusively for any data retrieval inside them.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.