Quick answer
- In 1bench
- Right-click the table in the sidebar, choose Truncate Table, type TRUNCATE and click Truncate Table.
- In SQL
- sql
TRUNCATE TABLE order_items;It resets AUTO_INCREMENT and commits on the spot, so it cannot be rolled back. A table that another table references fails with ERROR 1701.
Truncate a table visually in 1bench
1bench empties a MySQL table from the sidebar's right-click menu and asks you to type a confirmation word first, so a stray click cannot wipe a table.
Prerequisite: download 1bench. Free 7-day trial, no sign-up.
- 1
Open the connection
Connect to your MySQL server in 1bench and expand the database in the sidebar.
- 2
Choose Truncate Table
Right-click the table and choose Truncate Table. Views do not get this option, and on a read-only connection it is greyed out.
- 3
Type TRUNCATE to confirm
The Truncate Table dialog warns that this will permanently delete all data in the table and keep its structure. The Truncate Table button stays disabled until you type TRUNCATE in the box.
- 4
Check the result
A toast reports Truncated followed by the table name, and the open table refreshes empty. If MySQL refuses, the toast starts with Failed: and shows the server's error.
- 1bench runs a plain TRUNCATE TABLE with no other statements around it. A table that another table points to with a foreign key, such as users in the demo database, fails with ERROR 1701. Use the SET FOREIGN_KEY_CHECKS script below in the Query panel instead (open any table and click Query in the bottom bar).
- SET FOREIGN_KEY_CHECKS = 0 typed in the Query panel does not carry over to the right-click Truncate Table, which runs on a different connection. Put the TRUNCATE statements in the same Query panel script.
- The AUTO_INCREMENT counter goes back to 1, and there is no undo. Export the table first if you might want the rows back.
- Import Data has its own Clear target table before importing option. On InnoDB it deletes the rows inside the import's transaction, so a failed import puts them back.
Truncate a table with SQL
deletes every row in a table and keeps the table, its columns, indexes and grants. MySQL does this by dropping and recreating the table, so it takes a fraction of a second whatever the size, resets and cannot be undone.
TRUNCATE TABLE order_items;
The examples use the 1bench demo database, , where , and reference , and references and . Every statement was run on MySQL 8.4 LTS and 9.7, and they behave the same on both.
TRUNCATE TABLE syntax
The full syntax is one table name, with the keyword optional. There is no , no , no and no way to list several tables.
TRUNCATE TABLE order_items;
TRUNCATE order_items;
TRUNCATE TABLE saas_app.order_items;
MySQL answers however many rows were removed, because it never counts them. A view is not a table here: on a view fails with . To remove only some rows, use .
Truncate a table with foreign keys
MySQL refuses to truncate a table that another table references, even when the referencing table is empty. Trying it on gives:
ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint (`saas_app`.`orders`, CONSTRAINT `fk_orders_user`)
The message names only the first constraint it finds. on the child does not help, since TRUNCATE ignores it, and is a syntax error (ERROR 1064). List every table that points at the one you want to clear:
SELECT TABLE_NAME, CONSTRAINT_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_SCHEMA = 'saas_app'
AND REFERENCED_TABLE_NAME = 'users';
Then switch off foreign key checks for your session, truncate the children and the parent, and switch them back on. is a session setting, so all of it has to run on one connection.
Example: empty and everything that depends on it.
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE order_items;
TRUNCATE TABLE orders;
TRUNCATE TABLE subscriptions;
TRUNCATE TABLE audit_log_v2;
TRUNCATE TABLE users;
SET FOREIGN_KEY_CHECKS = 1;
Truncate the children too, not just the parent. With checks off, MySQL lets you truncate alone and leaves full of rows pointing at user ids that no longer exist. Since TRUNCATE also resets , the next user you insert gets id 1 and quietly inherits the old orders of user 1. Turning the checks back on does not re-check existing rows.
If you would rather keep foreign keys on, delete in dependency order instead (children first). It is slower, but every row is checked.
Reset AUTO_INCREMENT
TRUNCATE always resets the counter to 1, even when the table was created with a higher start such as . DELETE keeps counting from where it was.
Example: compare the next id after each.
TRUNCATE TABLE order_items;
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES (1, 1, 1, 9.99);
SELECT id FROM order_items; -- 1
DELETE FROM order_items;
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES (1, 1, 1, 9.99);
SELECT id FROM order_items; -- 2
To reset the counter after a DELETE, or to start somewhere other than 1 after a TRUNCATE, set it yourself. On an empty table InnoDB takes any value; on a table with rows it uses the next id above the current maximum.
ALTER TABLE order_items AUTO_INCREMENT = 1;
TRUNCATE vs DELETE vs DROP
All three get rid of rows, but they differ in what they keep and what they cost. The timings are from a 500,000-row InnoDB table on the same machine.
| TRUNCATE TABLE | DELETE FROM | DROP TABLE | |
|---|---|---|---|
| Removes | All rows | All rows, or those matching WHERE | Rows and the table itself |
| WHERE clause | No | Yes | No |
| Speed, 500k rows | 0.03 to 0.04 s | 0.9 s (9.7) to 1.9 s (8.4) | Fast |
| DELETE triggers fire | No | Yes, once per row | No |
| Rollback | No, implicit commit | Yes, inside a transaction | No, implicit commit |
| AUTO_INCREMENT | Reset to 1 | Kept | Gone with the table |
| Binary log (row format) | One statement, under 400 bytes | One event per batch of rows, 79 MB | One statement |
| Disk space | Returned to the OS | Kept in the .ibd file | Returned to the OS |
| Referenced by a foreign key | Fails, ERROR 1701 | Checked row by row | Fails, ERROR 3730 |
| Privilege needed | DROP | DELETE | DROP |
The binary log row matters on replicas: a DELETE of every row ships every row, while TRUNCATE ships one short statement even with . Use DELETE when you need a WHERE clause, triggers or a rollback, TRUNCATE to empty a table you are keeping, and DROP when the table itself should go.
TRUNCATE inside a transaction
TRUNCATE causes an implicit commit. Inside a transaction, it first commits whatever you had already done, then truncates, and a later ROLLBACK has nothing left to undo.
Example: the update survives the rollback, and so does the truncate.
START TRANSACTION;
UPDATE users SET status = 'inactive' WHERE id = 1;
TRUNCATE TABLE order_items;
ROLLBACK;
SELECT COUNT(*) FROM order_items; -- 0
SELECT status FROM users WHERE id = 1; -- inactive
If you need to empty a table and keep the option to back out, use inside the transaction instead.
Truncate all tables in a database
MySQL has no single statement for this. Generate one TRUNCATE per base table from , skipping views, and run the list with foreign key checks off.
SELECT CONCAT('TRUNCATE TABLE `', TABLE_NAME, '`;') AS stmt
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'saas_app'
AND TABLE_TYPE = 'BASE TABLE';
Example: do it in one line from the shell, which pipes the generated statements straight back into mysql.
mysql -u root -p -N -e "SELECT CONCAT('TRUNCATE TABLE \`', TABLE_NAME, '\`;') FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'saas_app' AND TABLE_TYPE = 'BASE TABLE'" \
| (echo 'SET FOREIGN_KEY_CHECKS = 0;'; cat) \
| mysql -u root -p saas_app
The order of the tables does not matter while the checks are off, and they are back on when that mysql session ends. To also remove the tables themselves, is shorter.
Truncate a partition
On a partitioned table, empties one or more partitions and leaves the rest. It is the fast way to purge old data from a table split by date.
Example: a log table partitioned by year.
CREATE TABLE events (
id INT NOT NULL,
created_at DATE NOT NULL,
PRIMARY KEY (id, created_at)
)
PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
ALTER TABLE events TRUNCATE PARTITION p2024;
ALTER TABLE events TRUNCATE PARTITION p2025, pmax;
ALTER TABLE events TRUNCATE PARTITION ALL;
A wrong name fails with . Do not check the result in : its column is an estimate from table statistics and can show 0 for partitions that still hold rows. Use instead.
TRUNCATE privileges
There is no TRUNCATE privilege in MySQL. TRUNCATE needs DROP on the table, and the DELETE privilege alone gets .
GRANT DROP ON saas_app.order_items TO 'app'@'%';
Grant it on single tables rather than the whole database where you can. The same privilege lets the user run , and in testing that is exactly what it allowed.
When TRUNCATE hangs
TRUNCATE needs an exclusive metadata lock on the table, so it waits for any open transaction that has read or written that table, even an idle one. While it waits, shows the state , and new queries on the table queue up behind it. The sys schema names the session in the way and writes the KILL statement for you:
SELECT object_name, waiting_pid, waiting_query, blocking_pid, sql_kill_blocking_connection
FROM sys.schema_table_lock_waits;
Commit in the blocking session, or run the it suggests, and TRUNCATE finishes at once. Killing the session rolls back its open transaction. To fail fast instead of waiting a year (the default is 31536000 seconds), set a short timeout first. The wait then ends with .
SET SESSION lock_wait_timeout = 10;
TRUNCATE TABLE order_items;