Error Message
ERROR 1264 (22003): Out of range value for column 'age' at row 1The same SQLSTATE 22003 covers every numeric type and the auto-increment ceiling. You will see it worded slightly differently depending on the column:
ERROR 1264 (22003): Out of range value for column 'price' at row 1
ERROR 1264 (22003): Out of range value for column 'id' at row 1
Warning 1264: Out of range value for column 'qty' at row 1That last line matters. In non-strict sql_mode, MySQL turns 1264 into a warning and quietly clamps the value to the column limit, so a number you thought you saved is now something else. Under STRICT_TRANS_TABLES, on by default since MySQL 5.7, it fails instead. Keep strict mode on. A loud error beats silent data corruption every time.
What Triggers This Error
The value does not fit the column's numeric range. Five situations produce it, and the fix is different for each:
- Value exceeds the integer type: a
TINYINTgot something over 127, or anINTgot something over 2,147,483,647. - Negative value into an
UNSIGNEDcolumn: there is no room below zero, so-1overflows. DECIMAL(p,s)precision overflow: the integer part has more digits thanp − sallows.- Arithmetic or aggregate overflow: a
SUM(), a multiplication, or a running total grew past the result type. - Auto-increment hit the ceiling: an
INTprimary key reached ~2.1 billion and cannot advance.
Bulk loads hit all five, just one row at a time. Find the offending row before you reach for a config change.
Fix by Scenario
Value exceeds the integer type
MySQL integer types are narrower than people expect. TINYINT stops at 127 signed (255 unsigned), SMALLINT at 32,767, MEDIUMINT at about 8.3 million, INT at about 2.1 billion. A counter that looked safe at launch outgrows SMALLINT faster than you would guess.
SELECT COLUMN_NAME, COLUMN_TYPE
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'people' AND COLUMN_NAME = 'age';If the data is real, widen the type:
ALTER TABLE people MODIFY age INT NOT NULL;
If the data is wrong, a parsing bug or a misplaced decimal, fix it at the source. Widening the column just hides the bug.
Negative value into an UNSIGNED column
UNSIGNED columns reject anything below zero. This usually shows up on a balance or quantity column that someone declared UNSIGNED because "it's always positive," right up until the first refund.
UPDATE accounts SET balance = balance - 100 WHERE id = 7;
-- ERROR 1264 (22003): Out of range value for column 'balance' at row 1If negatives are legitimate, drop UNSIGNED:
ALTER TABLE accounts MODIFY balance BIGINT NOT NULL DEFAULT 0;DECIMAL(p, s) precision overflow
DECIMAL(5,2) holds three digits before the decimal point, because p − s = 3. So 1000.00 overflows even though it reads as a small number. This catches people constantly.
INSERT INTO invoices (total) VALUES (1000.00);
-- ERROR 1264 (22003): Out of range value for column 'total' at row 1Widen the precision to match real invoice sizes:
ALTER TABLE invoices MODIFY total DECIMAL(12,2) NOT NULL;Arithmetic or aggregate overflow
Sometimes the column is fine and the expression over it is not:
SELECT SUM(amount) FROM ledger; -- result outgrows the inferred type
UPDATE counters SET n = n * 1000000; -- the product exceeds INTCast the operand to a wider type before the math runs:
SELECT SUM(CAST(amount AS DECIMAL(20,2))) FROM ledger;
ALTER TABLE counters MODIFY n BIGINT NOT NULL;Auto-increment reached the ceiling
The 2.1-billion wall. An INT primary key runs out of values, and because auto-increment never reuses the gaps left by deleted rows, a high-churn table gets there with far fewer than 2.1 billion live rows.
SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'events';Migrate the key to BIGINT. On a large table this rewrites every row, so run it in a maintenance window or with an online schema-change tool rather than a bare ALTER in the middle of the day.
ALTER TABLE events MODIFY id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;Bulk load or ETL row out of range
In strict mode, one bad value aborts the whole LOAD DATA or multi-row INSERT. Do not turn strict mode off to make the load pass. Find the row instead:
SELECT * FROM staging_orders WHERE qty > 32767 OR qty < -32768;Stage into a wide table, validate, then insert the good rows into production. Loosening sql_mode does not fix the load. It just pushes the corruption into clamped values you will not notice until a report looks wrong.
Prevention
- Size integer types to the real domain, and keep
STRICT_TRANS_TABLESon (the default as of MySQL 8.4) so overflows fail loudly. - Use
BIGINTfor any auto-increment key that could plausibly pass a few hundred million rows over its life. The four extra bytes per row are nothing next to a midnightINT → BIGINTmigration on a table that has already stopped accepting writes. - Pick
DECIMAL(p,s)precision from the largest legal amount, not the typical one. Money columns are where this bites. - Reserve
UNSIGNEDfor values that stay non-negative for the column's whole life. Refunds and corrections rarely qualify. - Validate numeric ranges in the application and in schema review, before the write reaches MySQL.
Bytebase's SQL Review can flag risky integer choices, such as an INT auto-increment primary key, during change review, catching the most common 1264 sources before they ship. See also ERROR 1406: Data Too Long for Column for the string-length version of the same problem.