MySQL
TinyINT
SQL Data Types
Database Optimization
SQL Numeric Limits

mysql tinyint1 vs tinyint2 vs tinyint3 vs tinyint4

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In MySQL, TINYINT(1), TINYINT(2), TINYINT(3), and TINYINT(4) all use the same underlying numeric storage. The number in parentheses does not change the byte size and does not change the numeric range. Historically, that number represented display width metadata, and even that behavior was mostly relevant only with ZEROFILL.

So if the real question is “does TINYINT(4) hold bigger values than TINYINT(1)?”, the answer is no. They are the same integer type. What changes the range is whether the column is signed or unsigned, not the number in parentheses.

Storage Size and Range Are the Same

A MySQL TINYINT always uses 1 byte of storage.

  • signed range: -128 to 127
  • unsigned range: 0 to 255

That is true regardless of whether the type is declared as TINYINT(1) or TINYINT(4).

sql
1CREATE TABLE demo (
2    a TINYINT(1),
3    b TINYINT(4),
4    c TINYINT(1) UNSIGNED,
5    d TINYINT(4) UNSIGNED
6);

Columns a and b have the same storage size and signed range. Columns c and d have the same storage size and unsigned range.

What the Number Historically Meant

The number in TINYINT(n) was historically the display width, not the value limit. It told some client tools how many digits to use when formatting values, especially alongside ZEROFILL.

sql
1CREATE TABLE display_demo (
2    code TINYINT(4) ZEROFILL
3);
4
5INSERT INTO display_demo (code) VALUES (7);
6SELECT code FROM display_demo;

A client could display that result as 0007, but the stored value is still just the number 7. The (4) does not create a wider numeric type.

In modern MySQL, display width for integer types has been deprecated and should not be used as though it carries business meaning.

Why TINYINT(1) Often Looks Special

Many developers associate TINYINT(1) with booleans because MySQL treats BOOLEAN and BOOL as aliases for TINYINT(1).

sql
1CREATE TABLE flags (
2    is_active BOOLEAN,
3    is_deleted BOOL
4);

Internally, those columns are still tiny integers. MySQL does not have a separate physical boolean storage type.

That can make TINYINT(1) look different from TINYINT(2) in ORMs or schema viewers, but the difference is mostly conventional. Some tools interpret TINYINT(1) as a boolean hint. The database engine still stores a tiny integer.

Choose the Type by Semantics, Not by Width

If the column stores a flag, declaring it as BOOLEAN can make the schema clearer even though MySQL implements it as TINYINT(1).

If the column stores a small numeric code, use TINYINT and decide signed versus unsigned based on the data domain.

What you should not do is choose TINYINT(4) because you believe it supports four-digit values. It does not. In current MySQL design, the practical choice is about semantics and range, not cosmetic width hints.

Common Pitfalls

The biggest mistake is assuming the number in parentheses controls storage size or maximum numeric value. It does not.

Another issue is treating TINYINT(1) as a true separate boolean storage type. In MySQL, it is still a tiny integer.

A third problem is relying on display width metadata in modern schemas. It is not a good tool for expressing business constraints.

Summary

  • 'TINYINT(1), TINYINT(2), TINYINT(3), and TINYINT(4) have the same 1-byte storage size.'
  • The number in parentheses does not change the numeric range.
  • Signed versus unsigned determines whether the range is -128..127 or 0..255.
  • 'TINYINT(1) is often used for booleans because BOOLEAN is an alias for it in MySQL.'
  • Do not use display width as though it were a data-capacity setting.

Course illustration
Course illustration

All Rights Reserved.