MySQL Data Types (INT, VARCHAR, DATE…)
In this lesson: MySQL data types explained — numeric, string, date/time — with sizes, examples and which type to choose.
Why data types matter
Every column in a MySQL table has a data type. It is a promise about what kind of value that column will hold — a whole number, a price, a name, a date, and so on. This one decision quietly controls three things: how much disk space each row uses, how fast your queries run, and whether wrong data can sneak in.
Picture a school database. If you store a student's fee as plain text, MySQL will happily accept "abc" as a fee. But if you declare that column as DECIMAL(10,2), the wrong value is blocked at the door and every price stays exact to the paisa. That is the real job of data types — they act like the shape of a container, so only the right thing fits inside.
MySQL groups its types into three practical families: numeric, string and date/time. If you understand one good example from each family, you can handle almost every real table.
Numeric types (INT, DECIMAL, FLOAT)
Numeric types store numbers, but they are not interchangeable. The key split is between exact types (INT, DECIMAL) and approximate types (FLOAT, DOUBLE).
| Type | Stores | Best for |
|---|---|---|
| TINYINT | Small whole numbers (0-255 unsigned) | Flags, age, status codes |
| INT | Whole numbers up to ~2.1 billion | IDs, roll numbers, counts |
| BIGINT | Very large whole numbers | Views, huge counters |
| DECIMAL(p,s) | Exact decimals with fixed scale | Money, fees, marks |
| FLOAT / DOUBLE | Approximate decimals | Scientific / sensor readings |
The word DECIMAL(10,2) means: up to 10 digits in total, with 2 of them after the decimal point. So the largest value is 99999999.99. This is the type you reach for whenever money is involved.
A value like 0.1 cannot be stored perfectly in FLOAT. Add many such values and the tiny errors pile up, so a bill that should read 100.00 might show 99.9998. Use DECIMAL for anything you will add up or display as currency.
String types (CHAR, VARCHAR, TEXT)
String types hold text. The two you will use every day are CHAR and VARCHAR, and the difference is about length.
| Type | Length behaviour | Best for |
|---|---|---|
| CHAR(n) | Fixed - always n characters, padded with spaces | Fixed-size codes (state code "UP", "MH") |
| VARCHAR(n) | Variable - uses only what is needed, up to n | Names, emails, addresses |
| TEXT | Large variable text, stored separately | Comments, remarks, descriptions |
Use CHAR only when the value is genuinely a fixed width. A 2-letter state code is a perfect fit. For a student's name — which could be 3 or 30 characters — VARCHAR wastes no space. Reach for TEXT only when you expect long paragraphs, because it cannot have a default value and is slower to index.
VARCHAR(50) does not grab 50 characters of space for every row. It stores exactly what you insert, plus a byte or two for the length. So a short name in a VARCHAR(255) column is not wasteful — the 255 is just the maximum you allow.
Date and time types
MySQL has dedicated types for dates and times, which is far better than storing them as plain strings. A real date type lets you sort chronologically, compare ranges, and use date functions like DATEDIFF().
| Type | Stores | Example |
|---|---|---|
| DATE | Only the date | 2026-06-01 |
| TIME | Only the time | 14:30:00 |
| DATETIME | Date + time, wide year range | 2026-06-01 14:30:00 |
| TIMESTAMP | Date + time, 1970-2038, time-zone aware | 2026-06-01 14:30:00 |
Use DATE for a birth date or admission date. Use DATETIME when you need the exact clock time of an event and want a wide range. Use TIMESTAMP when you want MySQL to auto-fill "created at" or "updated at" — but remember it stops working in the year 2038, so it is not for future planning dates.
A full CREATE TABLE example
Here is a small students table that puts one type from each family to work. Notice how each column's type matches the real thing it stores.
CREATE TABLE students (
roll_no INT PRIMARY KEY, -- whole number ID
name VARCHAR(50) NOT NULL, -- variable-length text
state CHAR(2), -- fixed 2-letter code
fees DECIMAL(10,2), -- exact money value
dob DATE, -- only a date
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO students (roll_no, name, state, fees, dob)
VALUES (1, 'Aarav Sharma', 'UP', 12500.00, '2008-04-15');
SELECT * FROM students;+---------+--------------+-------+----------+------------+---------------------+
| roll_no | name | state | fees | dob | joined_at |
+---------+--------------+-------+----------+------------+---------------------+
| 1 | Aarav Sharma | UP | 12500.00 | 2008-04-15 | 2026-06-01 14:30:00 |
+---------+--------------+-------+----------+------------+---------------------+
See how fees kept its two decimal places and joined_at filled itself in automatically because of DEFAULT CURRENT_TIMESTAMP. Each value landed in the right shape of container.
How to choose the right type
When you are unsure, ask three quick questions about the value:
- Is it a number I will do math on? Use
INTfor whole numbers,DECIMALfor money and marks. - Is it text of changing length? Use
VARCHAR. Only useCHARfor genuinely fixed-width codes, andTEXTfor long paragraphs. - Is it a date or time? Use
DATE,DATETIMEorTIMESTAMP— never a string, so date functions keep working.
One more rule: pick the smallest type that comfortably fits your data. A status flag that is only 0 or 1 does not need INT; TINYINT does the job in a quarter of the space. Across millions of rows, small choices like this add up to real speed.
Design a products table with columns for an id, a product name, a price and a "created at" time. Decide the type for each column before you write the SQL, then create it. Which column did you make DECIMAL, and why not FLOAT?
Common mistakes
- Using FLOAT for money. It looks fine on one row and quietly breaks totals. Always
DECIMALfor currency. - Storing dates as VARCHAR. A string date like "01-06-2026" cannot be sorted or compared correctly. Use a real
DATEtype. - Making everything VARCHAR(255) by habit. It works, but it hides the true shape of your data and lets wrong values in. Match the type to the meaning.
- Choosing TIMESTAMP for far-future dates. It stops at 2038. For dates beyond that, use
DATETIME.
Summary
- MySQL types fall into three families: numeric, string, and date/time.
- Use
INTfor whole numbers andDECIMALfor money and marks — neverFLOATfor currency. - Use
VARCHARfor most text,CHARonly for fixed-width codes,TEXTfor long content. - Use
DATE,DATETIMEorTIMESTAMPfor time — rememberTIMESTAMPends in 2038. - Pick the smallest type that fits; it saves space and speeds up queries.
Next, learn how to protect these columns further with rules using constraints in MySQL, or see how tables connect through a primary and foreign key.
Frequently Asked Questions
Which data type should I use for money in MySQL?
DECIMAL (for example DECIMAL(10,2)) for money. It stores the exact value, so 19.99 stays 19.99. Never use FLOAT or DOUBLE for money, because they store an approximate value and cause tiny rounding errors that add up in totals and bills.What is the difference between CHAR and VARCHAR?
CHAR(n) always uses a fixed length and pads shorter values with spaces, so it is best for values that are always the same size, like a 2-letter state code. VARCHAR(n) only uses the space the value actually needs, so it is better for names, emails and anything with a variable length.What is the difference between DATETIME and TIMESTAMP?
DATETIME stores the value exactly as you enter it and has a very wide year range. TIMESTAMP is stored internally in UTC, converts with the session time zone, and supports auto-updating the current time — but it only covers years 1970 to 2038, so it is not suitable for far-future dates.Does VARCHAR(255) waste space if I store a short name?
VARCHAR only stores the characters you actually put in, plus 1 to 2 bytes for the length. So a 5-letter name in a VARCHAR(255) column uses about the same space as in a VARCHAR(20) column. The number in brackets is a maximum limit, not a reserved block.