How to fix ERROR 1422 (HY000): Explicit or implicit commit is not allowed here in MySQL

MySQLINTERMEDIATEHIGHUpdated Dec 22, 2025· 148 views

This MySQL error occurs when you attempt to execute a COMMIT statement or an operation that causes an implicit commit inside a stored function or trigger, which MySQL does not permit. The error prevents transaction control statements from executing in these contexts.

Quick fix

Fixes 1422

-- Show the creation code of the stored function/trigger
SHOW CREATE FUNCTION function_name;
SHOW CREATE TRIGGER trigger_name;

-- Check for problematic statements in MySQL Workbench or command-line
-- Look for these keywords inside the function/trigger body:
-- - COMMIT
-- - ROLLBACK  
-- - START TRANSACTION or BEGIN (if not part of BEGIN...END block)
-- - TRUNCATE
-- - DDL statements (ALTER, CREATE, DROP)
-- - Administrative statements
  1. Identify where the error occurs in your stored object
  2. Remove explicit COMMIT and ROLLBACK statements from functions and triggers
  3. Replace TRUNCATE with DELETE in stored functions and triggers
  4. Avoid DDL statements inside stored functions and triggers
mysql — error
-- Show the creation code of the stored function/trigger
SHOW CREATE FUNCTION function_name;
SHOW CREATE TRIGGER trigger_name;
-- Check for problematic statements in MySQL Workbench or command-line
-- Look for these keywords inside the function/trigger body:
-- - COMMIT
-- - ROLLBACK
-- - START TRANSACTION or BEGIN (if not part of BEGIN...END block)
-- - TRUNCATE
-- - DDL statements (ALTER, CREATE, DROP)
-- - Administrative statements
ERROR 1422 (HY000): Explicit or implicit commit is not allowed here

What this error means

ERROR 1422 (HY000) is a MySQL restriction error that enforces a critical database design limitation: transaction control is not allowed within stored functions or triggers. Key aspects of this error: 1. **Transaction Control Restriction**: MySQL prohibits explicit COMMIT, ROLLBACK, and implicit commit-causing statements inside stored functions and triggers. This restriction maintains database consistency and prevents nested transaction issues. 2. **Explicit vs Implicit Commits**: An explicit COMMIT is obvious in the code, but implicit commits are caused by certain DDL statements (ALTER TABLE, CREATE TABLE, DROP TABLE, TRUNCATE, etc.) or transaction-control statements (BEGIN, LOCK TABLES, etc.) that automatically commit the current transaction. 3. **Stored Procedures vs Stored Functions**: Critically, stored procedures ARE allowed to contain COMMIT/ROLLBACK statements, but stored functions are NOT. If a stored procedure uses these statements, it cannot be called from within a function or trigger. 4. **Trigger Context**: Triggers execute as part of a parent statement's transaction. Allowing commits inside triggers would break transaction integrity and create cascading commit scenarios. 5. **Deadlock Scenario**: In rare cases, when InnoDB detects a deadlock, it may attempt rollback operations. If this occurs inside a trigger or function, MySQL raises error 1422 even without explicit commit statements in the code. This is a structural MySQL limitation designed to maintain ACID properties and prevent transaction nesting complications.

Typical symptoms

  • Stored function creation fails with "ERROR 1422" when code contains COMMIT or ROLLBACK
  • Trigger creation fails when using DDL statements like ALTER TABLE or TRUNCATE
  • Error occurs when calling a stored procedure that uses COMMIT from within a trigger
  • Application unable to create or alter database objects inside stored routines
  • TRUNCATE statement inside trigger raises error 1422
  • BEGIN...END blocks in stored functions cause unexpected error 1422
  • Error appears when using transaction-control statements in stored functions
  • Deadlock detection triggers error 1422 even without explicit commit statements

Common causes

  1. Explicit COMMIT statement inside a stored function or trigger
  2. Explicit ROLLBACK statement inside a stored function or trigger
  3. TRUNCATE statement inside a function or trigger (causes implicit commit)
  4. DDL statements (ALTER TABLE, CREATE TABLE, DROP TABLE, etc.) inside functions or triggers
  5. START TRANSACTION or BEGIN statement inside a stored function
  6. LOCK TABLES or UNLOCK TABLES statements inside functions or triggers
  7. User management statements (CREATE USER, DROP USER, GRANT, REVOKE) inside functions or triggers
  8. Administrative statements (FLUSH, RESET, OPTIMIZE TABLE) inside functions or triggers
  9. Calling a stored procedure that uses COMMIT from within a function or trigger
  10. SET autocommit = 1 statement inside a function or trigger
  11. InnoDB deadlock detection attempting rollback inside function/trigger context

How to fix "ERROR 1422 (HY000): Explicit or implicit commit is not allowed here"

1Identify where the error occurs in your stored object

First, locate the exact statement causing the error:

sql
-- Show the creation code of the stored function/trigger
SHOW CREATE FUNCTION function_name;
SHOW CREATE TRIGGER trigger_name;

-- Check for problematic statements in MySQL Workbench or command-line
-- Look for these keywords inside the function/trigger body:
-- - COMMIT
-- - ROLLBACK  
-- - START TRANSACTION or BEGIN (if not part of BEGIN...END block)
-- - TRUNCATE
-- - DDL statements (ALTER, CREATE, DROP)
-- - Administrative statements

Example problematic code:

sql
CREATE TRIGGER my_trigger AFTER INSERT ON users
FOR EACH ROW
BEGIN
  INSERT INTO audit_log VALUES (NEW.id, NOW());
  COMMIT;  -- ERROR 1422: This is not allowed in triggers
END;
sql
CREATE FUNCTION check_user(user_id INT) RETURNS BOOLEAN
BEGIN
  DECLARE count INT;
  SELECT COUNT(*) INTO count FROM users WHERE id = user_id;
  COMMIT;  -- ERROR 1422: Functions cannot have COMMIT
  RETURN count > 0;
END;
2Remove explicit COMMIT and ROLLBACK statements from functions and triggers

Remove transaction control statements from stored functions and triggers:

sql
-- WRONG: Function with COMMIT
CREATE FUNCTION get_user_count() RETURNS INT
BEGIN
  DECLARE cnt INT;
  SELECT COUNT(*) INTO cnt FROM users;
  COMMIT;  -- ERROR 1422
  RETURN cnt;
END;

-- CORRECT: Remove the COMMIT statement
CREATE FUNCTION get_user_count() RETURNS INT
BEGIN
  DECLARE cnt INT;
  SELECT COUNT(*) INTO cnt FROM users;
  RETURN cnt;
END;
sql
-- WRONG: Trigger with ROLLBACK
CREATE TRIGGER validate_user BEFORE INSERT ON users
FOR EACH ROW
BEGIN
  IF NEW.email IS NULL THEN
    ROLLBACK;  -- ERROR 1422
  END IF;
END;

-- CORRECT: Use SIGNAL to raise error instead
CREATE TRIGGER validate_user BEFORE INSERT ON users
FOR EACH ROW
BEGIN
  IF NEW.email IS NULL THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = 'Email cannot be null';
  END IF;
END;

The key principle: remove COMMIT/ROLLBACK entirely from functions and triggers.

3Replace TRUNCATE with DELETE in stored functions and triggers

TRUNCATE causes an implicit commit, so replace it with DELETE:

sql
-- WRONG: TRUNCATE in trigger (causes implicit commit)
CREATE TRIGGER reset_cache AFTER DELETE ON items
FOR EACH ROW
BEGIN
  TRUNCATE TABLE cache_table;  -- ERROR 1422
END;

-- CORRECT: Use DELETE instead
CREATE TRIGGER reset_cache AFTER DELETE ON items
FOR EACH ROW
BEGIN
  DELETE FROM cache_table;
END;
sql
-- WRONG: TRUNCATE in function
CREATE FUNCTION clear_logs() RETURNS INT
BEGIN
  TRUNCATE TABLE logs;  -- ERROR 1422
  RETURN 1;
END;

-- CORRECT: Use DELETE
CREATE FUNCTION clear_logs() RETURNS INT
BEGIN
  DELETE FROM logs;
  RETURN ROW_COUNT();
END;

Note: DELETE may be slower on large tables but preserves trigger context. For bulk operations, handle outside the trigger.

4Avoid DDL statements inside stored functions and triggers

DDL statements (ALTER TABLE, CREATE TABLE, DROP TABLE, etc.) cause implicit commits:

sql
-- WRONG: ALTER TABLE inside function
CREATE FUNCTION add_column() RETURNS INT
BEGIN
  ALTER TABLE users ADD COLUMN new_field INT;  -- ERROR 1422
  RETURN 1;
END;

-- CORRECT: Execute schema changes outside stored routines
-- Run DDL in application code, migrations, or manually:
ALTER TABLE users ADD COLUMN new_field INT;

-- Or use a stored procedure (not function) for complex operations
CREATE PROCEDURE schema_migration()
BEGIN
  -- Can use transaction control, but cannot be called from triggers
  ALTER TABLE users ADD COLUMN new_field INT;
  COMMIT;
END;

Best practice: Keep schema changes in application migrations or management scripts, not in functions/triggers.

5Use stored procedures instead of functions for transaction-heavy operations

If you need transaction control, use stored procedures (which allow COMMIT/ROLLBACK) instead of functions:

sql
-- WRONG: Function with complex transaction logic
CREATE FUNCTION transfer_money(from_id INT, to_id INT, amount DECIMAL) RETURNS BOOLEAN
BEGIN
  START TRANSACTION;  -- ERROR 1422
  UPDATE accounts SET balance = balance - amount WHERE id = from_id;
  UPDATE accounts SET balance = balance + amount WHERE id = to_id;
  COMMIT;  -- ERROR 1422
  RETURN TRUE;
END;

-- CORRECT: Use a stored procedure instead
CREATE PROCEDURE transfer_money(from_id INT, to_id INT, amount DECIMAL, OUT success BOOLEAN)
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    ROLLBACK;
    SET success = FALSE;
  END;

  START TRANSACTION;
  UPDATE accounts SET balance = balance - amount WHERE id = from_id;
  UPDATE accounts SET balance = balance + amount WHERE id = to_id;
  COMMIT;
  SET success = TRUE;
END;

-- Call the procedure from your application
CALL transfer_money(1, 2, 100.00, @success);
SELECT @success;

Key differences:
- Functions: Read-only, cannot modify database structure, no transaction control
- Procedures: Can modify data, control transactions, better for complex operations

Functions are meant for computation, procedures for business logic.

6Use SIGNAL and error handling instead of transaction rollback

In triggers and functions, use SIGNAL to raise errors instead of rollback:

sql
-- WRONG: Trying to rollback in trigger
CREATE TRIGGER validate_salary BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  IF NEW.salary < 0 THEN
    ROLLBACK;  -- ERROR 1422
  END IF;
END;

-- CORRECT: Use SIGNAL to raise error
CREATE TRIGGER validate_salary BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  IF NEW.salary < 0 THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = 'Salary cannot be negative';
  END IF;
END;
sql
-- Comprehensive error handling example
CREATE TRIGGER process_order BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
  -- Validate inventory
  IF (SELECT quantity FROM inventory WHERE product_id = NEW.product_id) < NEW.qty THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = 'Insufficient inventory';
  END IF;
  
  -- Validate customer
  IF NOT EXISTS (SELECT 1 FROM customers WHERE id = NEW.customer_id) THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = 'Customer not found';
  END IF;
  
  -- Update inventory (implicit part of trigger transaction)
  UPDATE inventory SET quantity = quantity - NEW.qty 
  WHERE product_id = NEW.product_id;
END;

SIGNAL raises an error that causes the parent statement to roll back naturally, without explicit ROLLBACK statements.

7Test and verify functions and triggers work without transaction control

After modifying your stored objects, test them thoroughly:

sql
-- Test function without transaction control
DELIMITER //

CREATE FUNCTION get_user_summary(user_id INT) RETURNS VARCHAR(500)
BEGIN
  DECLARE summary VARCHAR(500);
  SELECT CONCAT(first_name, ' ', last_name, ' - ', email)
  INTO summary
  FROM users
  WHERE id = user_id;
  RETURN COALESCE(summary, 'User not found');
END //

DELIMITER ;

-- Test the function
SELECT get_user_summary(1);
SELECT get_user_summary(999);  -- Non-existent user
sql
-- Test trigger behavior
DELIMITER //

CREATE TRIGGER log_user_creation AFTER INSERT ON users
FOR EACH ROW
BEGIN
  INSERT INTO audit_log (action, user_id, created_at) 
  VALUES ('CREATE_USER', NEW.id, NOW());
END //

DELIMITER ;

-- Test trigger by inserting data
INSERT INTO users (first_name, last_name, email) 
VALUES ('John', 'Doe', 'john@example.com');

-- Verify trigger executed
SELECT * FROM audit_log WHERE user_id = LAST_INSERT_ID();
sql
-- Verify error handling works
-- This INSERT should fail with trigger validation error
INSERT INTO employees (name, salary) VALUES ('Test', -1000);
-- Expected: Error 1644 - SIGNAL error from trigger validation

Verify that:
- Functions return correct values
- Triggers execute without ERROR 1422
- Data modifications occur as expected
- Error signals are raised properly

Advanced notes

Understanding MySQL transaction restrictions at a deeper level:

1. Transaction Context Isolation: Triggers execute as part of their parent statement's transaction. Allowing commits inside would break the atomic nature of the parent operation. For example, if an UPDATE statement with a trigger could commit partway through, it would violate ACID properties.

2. Nested Transactions Not Supported: MySQL does not support true nested transactions (unlike some other databases). Savepoints (SAVEPOINT/RELEASE SAVEPOINT) are allowed in triggers, but full transaction control is not.

3. Savepoint Exception: Interestingly, SAVEPOINT and ROLLBACK TO SAVEPOINT are allowed in triggers because they don't end the transaction - they only roll back to a specific point within it. This allows partial rollback without breaking the parent transaction.

4. Stored Procedure Calling Chain: The restriction is transitive: if a stored procedure uses COMMIT, and that procedure is called from a function (which is valid), it still cannot execute because the function context prevents it. The calling chain matters.

5. Implicit Commits in System Statements: User management statements (CREATE USER, GRANT, REVOKE) and administrative statements (FLUSH, RESET) cause implicit commits because they operate on system tables. These cannot be used in functions/triggers for the same reason.

6. Deadlock and Error Context: In concurrent scenarios, if InnoDB detects a deadlock within a trigger, it would internally attempt rollback. The error 1422 (confusing in this context) is MySQL's way of saying "you're in a context where transaction control is not allowed, so I can't handle this deadlock properly."

7. Alternative Patterns: For complex workflows:
- Event-Driven: Use triggers for simple operations; handle complex logic in application code
- Work Queue: Store pending operations in a table; process them via scheduled procedures or application jobs
- Outbox Pattern: Instead of multiple updates in a trigger, write to an "outbox" table and process asynchronously

8. Performance Implications: Avoiding transaction control in triggers means simpler, faster execution. Complex transaction logic should live in application code where it can be properly monitored and logged.

9. Version Compatibility: This restriction exists across all modern MySQL versions (5.7, 8.0, 8.1). MariaDB has similar restrictions with some extensions.

10. Debugging Tips: When error 1422 appears, check not just the immediate code, but all procedures/functions called within the trigger. The problematic statement might be nested several levels deep.

Frequently asked questions

What does "1422" mean?
ERROR 1422 (HY000) is a MySQL restriction error that enforces a critical database design limitation: transaction control is not allowed within stored functions or triggers. Key aspects of this error: 1. Transaction Control Restriction: MySQL prohibits explicit COMMIT, ROLLBACK, and implicit commit-causing statements inside stored functions and triggers.
How do I fix "1422"?
This MySQL error occurs when you attempt to execute a COMMIT statement or an operation that causes an implicit commit inside a stored function or trigger, which MySQL does not permit. The error prevents transaction control statements from executing in these contexts.
What causes "1422"?
Explicit COMMIT statement inside a stored function or trigger Explicit ROLLBACK statement inside a stored function or trigger TRUNCATE statement inside a function or trigger (causes implicit commit)
Is the "1422" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading