Skip to content

Commit 7425f30

Browse files
jipengfei-jpfclaude
andcommitted
feat(auto): add 9 posts — Postgres deferrable constraints, conflict with recovery, pg_stat_progress views, MySQL errors 1064/2002/1071/1366/1055/1175 (2026-09-27 SEO run)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a7164ce commit 7425f30

10 files changed

Lines changed: 5090 additions & 1744 deletions

‎pages/blog/mysql-error-1055-only-full-group-by.mdx‎

Lines changed: 364 additions & 0 deletions
Large diffs are not rendered by default.

‎pages/blog/mysql-error-1064-syntax-error.mdx‎

Lines changed: 478 additions & 0 deletions
Large diffs are not rendered by default.

‎pages/blog/mysql-error-1071-specified-key-too-long.mdx‎

Lines changed: 361 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
---
2+
title: "MySQL Error 1175: You Are Using Safe Update Mode"
3+
description: "Fix MySQL error 1175 safe update mode: what sql_safe_updates checks, Workbench and --safe-updates settings, key-based WHERE clauses and batched bulk deletes."
4+
image: "/blog/image/9908.jpg"
5+
category: "Technical Article"
6+
date: September 27, 2026
7+
---
8+
[![Click to use](/image/blog/bg/chat2db1.png)](https://app.chat2db.ai/)
9+
# MySQL Error 1175: You Are Using Safe Update Mode
10+
11+
import Authors, { Author } from "components/authors";
12+
13+
<Authors date="September 27, 2026">
14+
<Author name="Chat2DB Team" link="https://chat2db.ai" />
15+
</Authors>
16+
17+
MySQL error 1175 is a guard rail, not a bug. It appears when the `sql_safe_updates` setting is on and you run an `UPDATE` or `DELETE` that MySQL considers too broad: one that does not restrict rows through a key and has no `LIMIT`. Most people meet it for the first time in MySQL Workbench, which enables safe updates by default, while running a perfectly intentional statement such as clearing a staging table.
18+
19+
The quick answer is `SET SQL_SAFE_UPDATES = 0;`. This article explains what the check actually looks at, where the setting comes from (Workbench, the `mysql` client, option files), how to turn it off for just one statement's worth of work and back on, and how to write updates and bulk deletes that pass the check without disabling it. Examples are for MySQL 8.0 and 8.4; MariaDB behaves the same unless noted.
20+
21+
## The error message
22+
23+
```sql
24+
CREATE TABLE sessions (
25+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
26+
user_id INT NOT NULL,
27+
token CHAR(64) NOT NULL,
28+
expires_at DATETIME NOT NULL,
29+
status VARCHAR(20) NOT NULL DEFAULT 'active',
30+
KEY idx_expires (expires_at),
31+
KEY idx_user (user_id)
32+
);
33+
34+
SET SQL_SAFE_UPDATES = 1;
35+
36+
DELETE FROM sessions WHERE status = 'revoked';
37+
```
38+
39+
```text
40+
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column. To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect.
41+
```
42+
43+
In MySQL Workbench the same message appears in the Output panel as `Error Code: 1175`. The hint about "Preferences -> SQL Editor" is part of the server's message text, which is why it shows up even in the command-line client where there is no Preferences menu.
44+
45+
The statement above is rejected because `status` has no index. MySQL would have to scan the whole table to find matching rows, and that is exactly the pattern safe update mode is designed to stop.
46+
47+
## What sql_safe_updates actually checks
48+
49+
With `sql_safe_updates = 1`, an `UPDATE` or `DELETE` statement is allowed only if at least one of these is true:
50+
51+
1. The `WHERE` clause restricts rows through a key (an indexed column) that the optimizer can actually use to find the rows.
52+
2. The statement has a `LIMIT` clause.
53+
54+
Some examples against the `sessions` table:
55+
56+
```sql
57+
-- Allowed: primary key in WHERE
58+
DELETE FROM sessions WHERE id = 42;
59+
60+
-- Allowed: range on an indexed column
61+
DELETE FROM sessions WHERE expires_at < '2026-09-01';
62+
63+
-- Allowed: LIMIT, even without a key
64+
UPDATE sessions SET status = 'revoked' WHERE status = 'suspicious' LIMIT 1000;
65+
66+
-- Rejected: no WHERE, no LIMIT
67+
DELETE FROM sessions;
68+
69+
-- Rejected: WHERE on a non-indexed column, no LIMIT
70+
UPDATE sessions SET status = 'expired' WHERE status = 'active';
71+
```
72+
73+
A few subtleties are worth knowing.
74+
75+
**The key must be usable.** The check is about whether rows are located through an index, not whether an indexed column appears somewhere in the text. Wrapping the column in a function prevents index use, so this can still be rejected:
76+
77+
```sql
78+
-- Can be rejected: DATE() on the column prevents a range scan on idx_expires
79+
DELETE FROM sessions WHERE DATE(expires_at) < '2026-09-01';
80+
```
81+
82+
Rewrite it as a plain range, which is also faster:
83+
84+
```sql
85+
DELETE FROM sessions WHERE expires_at < '2026-09-01 00:00:00';
86+
```
87+
88+
The same applies to comparisons that force a type conversion, for example comparing an indexed `VARCHAR` column to a number.
89+
90+
**OR with a non-indexed column** can also turn a key lookup into a full scan and trigger the error:
91+
92+
```sql
93+
-- Can be rejected: the second condition has no index
94+
DELETE FROM sessions WHERE user_id = 7 OR status = 'revoked';
95+
```
96+
97+
**TRUNCATE is not affected.** `TRUNCATE TABLE sessions;` is a DDL statement and is not checked by `sql_safe_updates`. It also cannot be rolled back and resets `AUTO_INCREMENT`, so safe update mode does not make it any less dangerous.
98+
99+
**Multi-table statements** follow the same idea: the rows in the tables being modified must be found through keys.
100+
101+
## Where safe update mode comes from
102+
103+
`sql_safe_updates` defaults to `OFF` on the server. If you are seeing error 1175, something switched it on for your session. There are three usual sources.
104+
105+
### MySQL Workbench
106+
107+
Workbench turns on safe updates for its SQL editor by default. To change it:
108+
109+
1. Open **Edit > Preferences** (on macOS: **MySQLWorkbench > Settings** or **Preferences**, depending on the version).
110+
2. Go to **SQL Editor**.
111+
3. Uncheck **Safe Updates (rejects UPDATEs and DELETEs with no restrictions)**.
112+
4. Click **OK**, then reconnect with **Query > Reconnect to Server** or by closing and reopening the connection tab.
113+
114+
The reconnect step is required. Workbench applies the setting when it opens the session, so changing the checkbox does not affect the connection you already have open. This is the most common reason people report that "unchecking the box didn't work".
115+
116+
### The mysql client with --safe-updates
117+
118+
The command-line client has an option that turns on safe updates for the session:
119+
120+
```bash
121+
mysql --safe-updates -u app -p shop
122+
# identical, with a memorable name:
123+
mysql --i-am-a-dummy -u app -p shop
124+
```
125+
126+
It can also be set in an option file, which is easy to forget about:
127+
128+
```ini
129+
[mysql]
130+
safe-updates
131+
```
132+
133+
`--safe-updates` does more than set `sql_safe_updates`. When the client connects, it runs the equivalent of:
134+
135+
```sql
136+
SET sql_safe_updates = 1, sql_select_limit = 1000, max_join_size = 1000000;
137+
```
138+
139+
- `sql_select_limit = 1000` caps `SELECT` results at 1,000 rows unless the statement has its own `LIMIT`. This is the source of "why does my query only return 1000 rows?" in sessions started with this option.
140+
- `max_join_size = 1000000` rejects `SELECT` statements the optimizer estimates will examine more than a million row combinations, with error 1104 ("The SELECT would examine more than MAX_JOIN_SIZE rows").
141+
142+
Both values can be changed with the client options `--select-limit` and `--max-join-size`:
143+
144+
```bash
145+
mysql --safe-updates --select-limit=5000 --max-join-size=10000000 -u app -p shop
146+
```
147+
148+
To find out whether an option file is enabling it, print the options the client would use:
149+
150+
```bash
151+
mysql --print-defaults
152+
```
153+
154+
### Application or connection pool settings
155+
156+
Some tools and pools run initialization SQL on each connection. Search for `sql_safe_updates` in your application configuration, connection pool `initSql` settings, or JDBC `sessionVariables`. A server-wide `SET GLOBAL sql_safe_updates = 1` or a `sql_safe_updates` line under `[mysqld]` in `my.cnf` also enables it for every new session:
157+
158+
```sql
159+
SELECT @@GLOBAL.sql_safe_updates, @@SESSION.sql_safe_updates;
160+
```
161+
162+
## Turning it off for a session, then back on
163+
164+
When you have a legitimate statement that cannot use a key, disable the check for your session, run the statement, and turn it back on:
165+
166+
```sql
167+
SET SQL_SAFE_UPDATES = 0;
168+
169+
UPDATE sessions SET status = 'expired' WHERE status = 'active' AND expires_at < NOW();
170+
171+
SET SQL_SAFE_UPDATES = 1;
172+
```
173+
174+
`SET SQL_SAFE_UPDATES = 0` without `GLOBAL` affects only the current connection. Other users and other Workbench tabs are unaffected. Avoid `SET GLOBAL sql_safe_updates = 0`: it changes the default for every new connection on the server, and if it was enabled globally, someone chose that on purpose.
175+
176+
Wrapping the change in a transaction adds a second safety net, because you can check the affected row count before committing:
177+
178+
```sql
179+
SET SQL_SAFE_UPDATES = 0;
180+
START TRANSACTION;
181+
182+
DELETE FROM sessions WHERE status = 'revoked';
183+
-- Query OK, 18234 rows affected
184+
185+
SELECT ROW_COUNT(); -- run immediately after the DELETE
186+
-- If the number looks wrong:
187+
ROLLBACK;
188+
-- If it looks right:
189+
COMMIT;
190+
191+
SET SQL_SAFE_UPDATES = 1;
192+
```
193+
194+
This works for InnoDB tables. Tables using MyISAM or other non-transactional engines cannot be rolled back.
195+
196+
## Writing statements that pass the check
197+
198+
Turning the check off is fine for one-off maintenance, but for code that runs repeatedly it is better to write statements that pass it. That usually also makes them faster.
199+
200+
### Use the primary key
201+
202+
The most robust pattern is to find the rows first, then modify them by primary key:
203+
204+
```sql
205+
SELECT id FROM sessions WHERE status = 'revoked';
206+
207+
DELETE FROM sessions WHERE id IN (101, 102, 250);
208+
```
209+
210+
For larger sets, collect the IDs in a temporary table and join on the primary key, so the rows of `sessions` are located through `PRIMARY`:
211+
212+
```sql
213+
CREATE TEMPORARY TABLE doomed (id BIGINT PRIMARY KEY);
214+
215+
INSERT INTO doomed (id)
216+
SELECT id FROM sessions WHERE status = 'revoked';
217+
218+
DELETE s
219+
FROM sessions s
220+
JOIN doomed d ON d.id = s.id;
221+
222+
DROP TEMPORARY TABLE doomed;
223+
```
224+
225+
Whether safe update mode accepts a particular multi-table form depends on the plan the optimizer picks; if it is still rejected, the batching patterns below always work.
226+
227+
A common shortcut is `WHERE id > 0` to satisfy the check while updating the whole table. It works, since it is a range on the primary key, but it only defeats the protection. If you really mean the whole table, say so explicitly by disabling the check for the session.
228+
229+
### Add the index the WHERE clause needs
230+
231+
If a query like `UPDATE ... WHERE status = ...` runs regularly, the error is a hint that it does a full table scan every time. An index fixes both problems:
232+
233+
```sql
234+
ALTER TABLE sessions ADD INDEX idx_status (status);
235+
```
236+
237+
Low-selectivity columns such as `status` are not always good index candidates; a composite index that matches the actual filter, such as `(status, expires_at)`, is often better.
238+
239+
### Use LIMIT
240+
241+
`LIMIT` alone satisfies the check, and it is the foundation of safe bulk changes. Remember that `LIMIT` without `ORDER BY` in an `UPDATE` or `DELETE` removes an unspecified subset of rows. That is fine when you repeat the statement until nothing matches, but not when you mean "the oldest 1,000 rows".
242+
243+
## Safe bulk deletes in batches
244+
245+
Deleting millions of rows in one statement holds locks for a long time, generates a huge undo log, and can cause replication lag. Deleting in batches is kinder to the server and naturally compatible with safe update mode.
246+
247+
### Batch by LIMIT
248+
249+
```sql
250+
DELETE FROM sessions
251+
WHERE expires_at < '2026-09-01'
252+
ORDER BY id
253+
LIMIT 5000;
254+
```
255+
256+
Repeat until the statement reports `0 rows affected`. A shell loop does that for you:
257+
258+
```bash
259+
#!/usr/bin/env bash
260+
set -euo pipefail
261+
262+
while true; do
263+
deleted=$(mysql --safe-updates -N -u app -p"$DB_PASSWORD" shop -e "
264+
DELETE FROM sessions
265+
WHERE expires_at < '2026-09-01'
266+
ORDER BY id
267+
LIMIT 5000;
268+
SELECT ROW_COUNT();")
269+
echo "deleted: $deleted"
270+
[ "$deleted" -eq 0 ] && break
271+
sleep 0.5
272+
done
273+
```
274+
275+
`ROW_COUNT()` must run in the same session right after the `DELETE`, which is why both statements are in one `-e` string. The short sleep gives replicas time to catch up. Passing the password on the command line is shown for brevity; in practice use an option file or `mysql_config_editor`.
276+
277+
### Batch by primary key range
278+
279+
For very large tables, `ORDER BY id LIMIT n` has to skip over already-deleted ranges less and less efficiently as rows are purged from the middle. Walking the primary key in ranges avoids that:
280+
281+
```sql
282+
SELECT MIN(id), MAX(id) FROM sessions WHERE expires_at < '2026-09-01';
283+
-- 1, 48210000
284+
```
285+
286+
```sql
287+
DELETE FROM sessions
288+
WHERE id BETWEEN 1 AND 10000
289+
AND expires_at < '2026-09-01';
290+
291+
DELETE FROM sessions
292+
WHERE id BETWEEN 10001 AND 20000
293+
AND expires_at < '2026-09-01';
294+
-- ... continue up to MAX(id)
295+
```
296+
297+
Each statement uses the primary key, so it passes safe update mode, touches a bounded number of rows, and holds locks briefly. The same idea as a stored procedure:
298+
299+
```sql
300+
DELIMITER //
301+
CREATE PROCEDURE purge_sessions(IN cutoff DATETIME, IN step INT)
302+
BEGIN
303+
DECLARE lo BIGINT;
304+
DECLARE hi BIGINT;
305+
SELECT MIN(id), MAX(id) INTO lo, hi FROM sessions WHERE expires_at < cutoff;
306+
WHILE lo IS NOT NULL AND lo <= hi DO
307+
DELETE FROM sessions
308+
WHERE id BETWEEN lo AND lo + step - 1
309+
AND expires_at < cutoff;
310+
COMMIT;
311+
SET lo = lo + step;
312+
END WHILE;
313+
END //
314+
DELIMITER ;
315+
316+
CALL purge_sessions('2026-09-01 00:00:00', 10000);
317+
```
318+
319+
The same batching applies to bulk `UPDATE`s. When child tables reference the rows you delete, make sure the foreign key has `ON DELETE CASCADE` or delete children first; otherwise the batches fail with the errors described in [MySQL Error 1452: Foreign Key Constraint Fails](/resources/blog/mysql-error-1452-foreign-key-constraint-fails).
320+
321+
If you prefer to run maintenance statements from a GUI, [Chat2DB](https://chat2db.ai/download) shows the affected row count for every statement and lets you keep a transaction open while you check it, which pairs well with batch deletes.
322+
323+
## MariaDB differences
324+
325+
MariaDB supports the same `sql_safe_updates` variable, the same error 1175, and the same `--safe-updates` and `--i-am-a-dummy` client options with the same `sql_select_limit` and `max_join_size` defaults. The exact wording of error messages can differ slightly between MariaDB and MySQL versions, so match on the error number rather than the text in scripts. `TRUNCATE` is likewise not covered by the check.
326+
327+
## When the error number is different
328+
329+
Safe update mode only produces error 1175 (and error 1104 from `max_join_size` in client sessions started with `--safe-updates`). If your `UPDATE` fails with another code, such as a duplicate key error or an access denied error, see [MySQL Error 1062](/resources/blog/mysql-error-1062-duplicate-entry) or [MySQL Error 1045](/resources/blog/mysql-error-1045). You can also look up any MySQL error number and its meaning with the free [MySQL error code lookup tool](https://chat2db.ai/tools/mysql-error-code-lookup).
330+
331+
## FAQ
332+
333+
### How do I fix error 1175 in MySQL Workbench permanently?
334+
335+
Go to Edit > Preferences > SQL Editor, uncheck Safe Updates, click OK, and reconnect to the server. The change applies only to new connections, so the reconnect is required. For a one-off statement, `SET SQL_SAFE_UPDATES = 0;` in the editor is enough.
336+
337+
### Is it safe to run SET SQL_SAFE_UPDATES = 0?
338+
339+
It affects only your current session, so it does not change anything for other users. The risk is that your own next statement is no longer checked. Turn it back on with `SET SQL_SAFE_UPDATES = 1;` after the maintenance statement, and use a transaction so you can roll back if the row count is wrong.
340+
341+
### Why is my UPDATE rejected even though the WHERE uses an indexed column?
342+
343+
Because the optimizer could not use the index to find the rows. Functions on the column, type conversions, and `OR` conditions on non-indexed columns all force a full scan. Rewrite the condition as a plain comparison or range on the indexed column, or add `LIMIT`.
344+
345+
### Why does my SELECT only return 1000 rows?
346+
347+
The session was started with `mysql --safe-updates` (or `safe-updates` in an option file), which also sets `sql_select_limit = 1000`. Add an explicit `LIMIT`, run `SET sql_select_limit = DEFAULT;`, or start the client with `--select-limit` set to a larger value.

0 commit comments

Comments
 (0)