MySQL CREATE TABLE Syntax: Complete Reference Guide

The CREATE TABLE statement is one of the most fundamental commands in MySQL, allowing you to define the structure of your database tables. Whether you're designing a simple blog or a complex e-commerce platform, understanding the full capabilities of MySQL's table creation syntax is essential for building efficient, well-structured databases.

In this comprehensive guide, we'll explore every aspect of the CREATE TABLE statement, from basic syntax to advanced features like foreign keys, indexes, and table options. By the end, you'll have a complete reference for creating robust MySQL table schemas.

Basic CREATE TABLE Syntax

The basic structure of a CREATE TABLE statement follows this pattern:

CREATE TABLE table_name (
    column_name1 data_type constraints,
    column_name2 data_type constraints,
    ...
    table_constraints
) table_options;

Let's break down each component:

Here's a simple example:

CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

This creates a users table with four columns: an auto-incrementing ID, a unique username, a required email address, and a timestamp that automatically records when the row was created.

MySQL Data Types Reference

Choosing the right data type is crucial for database performance and data integrity. MySQL supports a wide variety of data types, which can be categorized into several groups:

Numeric Types

Data Type Description Storage Example
TINYINT Very small integer. Range: -128 to 127 (signed) or 0 to 255 (unsigned) 1 byte age TINYINT UNSIGNED
SMALLINT Small integer. Range: -32,768 to 32,767 (signed) 2 bytes port_number SMALLINT
MEDIUMINT Medium-sized integer. Range: -8,388,608 to 8,388,607 3 bytes population MEDIUMINT
INT Standard integer. Range: -2,147,483,648 to 2,147,483,647 4 bytes user_id INT
BIGINT Large integer. Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 8 bytes transaction_id BIGINT
DECIMAL(M,D) Fixed-point number with M total digits and D decimal places. Ideal for financial data Varies price DECIMAL(10,2)
FLOAT Single-precision floating-point number 4 bytes temperature FLOAT
DOUBLE Double-precision floating-point number 8 bytes coordinates DOUBLE

String Types

Data Type Description Max Length Example
CHAR(N) Fixed-length string. Padded with spaces if shorter than N 255 characters country_code CHAR(2)
VARCHAR(N) Variable-length string. Uses only as much storage as needed 65,535 bytes username VARCHAR(50)
TINYTEXT Very small text string 255 bytes short_note TINYTEXT
TEXT Standard text string. Good for articles, descriptions 65,535 bytes article_body TEXT
MEDIUMTEXT Medium-length text 16 MB book_content MEDIUMTEXT
LONGTEXT Very large text string 4 GB xml_data LONGTEXT
ENUM('val1','val2',...) Enumeration: column can only contain one value from a predefined list 1-2 bytes status ENUM('active','inactive')
SET('val1','val2',...) Set: column can contain zero or more values from a predefined list 1-8 bytes permissions SET('read','write','delete')

Date and Time Types

Data Type Description Format Example
DATE Date only (no time component) YYYY-MM-DD birth_date DATE
TIME Time only (no date component) HH:MM:SS duration TIME
DATETIME Date and time combination. Range: 1000-01-01 to 9999-12-31 YYYY-MM-DD HH:MM:SS appointment DATETIME
TIMESTAMP Date and time. Automatically updates on row modification if configured. Range: 1970-01-01 to 2038-01-19 YYYY-MM-DD HH:MM:SS created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
YEAR Year value only YYYY manufacture_year YEAR

Other Types

Data Type Description Example
BOOLEAN Boolean value. In MySQL, BOOLEAN is an alias for TINYINT(1). 0 = false, non-zero = true is_active BOOLEAN
JSON JavaScript Object Notation. Stores JSON documents with automatic validation metadata JSON
BLOB Binary Large Object. For storing binary data like images or files image_data BLOB

Column Constraints

Constraints enforce rules on the data in your tables, ensuring data integrity and consistency. Here are the most commonly used column constraints:

NOT NULL

Ensures that a column cannot have a NULL value. This is essential for required fields.

CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100)
);

DEFAULT

Sets a default value for a column when no value is specified during insertion.

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    status VARCHAR(20) DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    quantity INT DEFAULT 1
);

AUTO_INCREMENT

Automatically generates a unique numeric value for each new row. Typically used with primary keys. Only one AUTO_INCREMENT column per table is allowed, and it must be indexed.

CREATE TABLE products (
    product_id INT AUTO_INCREMENT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    price DECIMAL(10,2)
);

UNIQUE

Ensures that all values in a column are different. Multiple UNIQUE constraints can exist in a single table.

CREATE TABLE users (
    user_id INT PRIMARY KEY,
    username VARCHAR(50) UNIQUE,
    email VARCHAR(100) UNIQUE,
    phone VARCHAR(20)
);

PRIMARY KEY

Uniquely identifies each row in a table. A table can have only one primary key, which can consist of a single column or multiple columns (composite key). Primary keys implicitly include NOT NULL and UNIQUE constraints.

-- Single column primary key
CREATE TABLE categories (
    category_id INT PRIMARY KEY,
    category_name VARCHAR(50)
);

-- Composite primary key
CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

Foreign Key Constraints

Foreign keys establish relationships between tables by referencing the primary key of another table. They enforce referential integrity, preventing orphaned records.

Basic Foreign Key Syntax

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    user_id INT,
    order_date DATE,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

ON DELETE and ON UPDATE Options

Foreign keys support actions that determine what happens when the referenced row is deleted or updated:

CREATE TABLE posts (
    post_id INT PRIMARY KEY,
    author_id INT,
    title VARCHAR(200),
    content TEXT,
    FOREIGN KEY (author_id) REFERENCES users(user_id)
        ON DELETE CASCADE
        ON UPDATE CASCADE
);

In this example, if a user is deleted, all their posts are automatically deleted. If a user's ID is updated, the change cascades to all related posts.

Table Options

Table options allow you to configure storage engine, character encoding, and other table-level settings:

ENGINE

Specifies the storage engine. InnoDB is the default and recommended engine for most use cases due to its support for transactions and foreign keys.

CREATE TABLE transactions (
    transaction_id BIGINT PRIMARY KEY,
    amount DECIMAL(10,2),
    description VARCHAR(255)
) ENGINE=InnoDB;

CHARSET and COLLATE

Define the character set and collation for the table. UTF8MB4 is recommended for full Unicode support, including emojis.

CREATE TABLE multilingual_content (
    content_id INT PRIMARY KEY,
    text_value TEXT
) CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

COMMENT

Add a descriptive comment to the table for documentation purposes.

CREATE TABLE audit_log (
    log_id BIGINT PRIMARY KEY,
    action VARCHAR(50),
    timestamp TIMESTAMP
) COMMENT='Stores all user actions for auditing purposes';

Indexes

Indexes improve query performance by allowing MySQL to quickly locate rows without scanning the entire table. However, they also consume storage space and slow down write operations, so use them judiciously.

PRIMARY KEY Index

Every table should have a primary key, which automatically creates a clustered index.

CREATE TABLE users (
    user_id INT PRIMARY KEY,
    username VARCHAR(50)
);

UNIQUE INDEX

Creates a unique index that enforces uniqueness and improves lookup performance.

CREATE TABLE users (
    user_id INT PRIMARY KEY,
    email VARCHAR(100),
    UNIQUE INDEX idx_email (email)
);

Regular INDEX

Creates a non-unique index to speed up queries on frequently searched columns.

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    user_id INT,
    status VARCHAR(20),
    INDEX idx_user_status (user_id, status)
);

FULLTEXT INDEX

Enables full-text search capabilities on TEXT or VARCHAR columns. Useful for search functionality.

CREATE TABLE articles (
    article_id INT PRIMARY KEY,
    title VARCHAR(200),
    body TEXT,
    FULLTEXT INDEX ft_search (title, body)
);

-- Usage example
SELECT * FROM articles 
WHERE MATCH(title, body) AGAINST('database optimization');

Complete Example: E-commerce Database

Let's put everything together with a complete e-commerce database schema that demonstrates real-world usage of MySQL CREATE TABLE syntax:

-- Users table
CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    phone VARCHAR(20),
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_email (email)
) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Registered users of the e-commerce platform';

-- Product categories
CREATE TABLE categories (
    category_id INT AUTO_INCREMENT PRIMARY KEY,
    category_name VARCHAR(100) NOT NULL,
    description TEXT,
    parent_category_id INT,
    FOREIGN KEY (parent_category_id) REFERENCES categories(category_id)
        ON DELETE SET NULL
        ON UPDATE CASCADE
) ENGINE=InnoDB CHARSET=utf8mb4 COMMENT='Product categorization hierarchy';

-- Products table
CREATE TABLE products (
    product_id INT AUTO_INCREMENT PRIMARY KEY,
    sku VARCHAR(50) NOT NULL UNIQUE,
    product_name VARCHAR(200) NOT NULL,
    description TEXT,
    category_id INT,
    price DECIMAL(10,2) NOT NULL,
    stock_quantity INT DEFAULT 0,
    is_available BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (category_id) REFERENCES categories(category_id)
        ON DELETE SET NULL
        ON UPDATE CASCADE,
    INDEX idx_category (category_id),
    INDEX idx_price (price),
    FULLTEXT INDEX ft_product_search (product_name, description)
) ENGINE=InnoDB CHARSET=utf8mb4 COMMENT='Product catalog';

-- Orders table
CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    status VARCHAR(20) DEFAULT 'pending',
    total_amount DECIMAL(10,2) NOT NULL,
    shipping_address TEXT,
    billing_address TEXT,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
        ON DELETE CASCADE
        ON UPDATE CASCADE,
    INDEX idx_user_order (user_id, order_date),
    INDEX idx_status (status)
) ENGINE=InnoDB CHARSET=utf8mb4 COMMENT='Customer orders';

-- Order items (junction table for many-to-many relationship)
CREATE TABLE order_items (
    item_id INT AUTO_INCREMENT PRIMARY KEY,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL DEFAULT 1,
    unit_price DECIMAL(10,2) NOT NULL,
    subtotal DECIMAL(10,2) GENERATED ALWAYS AS (quantity * unit_price) STORED,
    FOREIGN KEY (order_id) REFERENCES orders(order_id)
        ON DELETE CASCADE
        ON UPDATE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products(product_id)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,
    UNIQUE INDEX idx_order_product (order_id, product_id)
) ENGINE=InnoDB CHARSET=utf8mb4 COMMENT='Individual items within orders';

This schema demonstrates several important concepts:

Visualize Your Schema with Free ER Diagram

Now that you understand MySQL CREATE TABLE syntax, wouldn't it be great to visualize your database schema? Our free online tool, Free ER Diagram, makes it easy to convert your SQL DDL statements into professional ER diagrams instantly.

Simply paste your CREATE TABLE statements into our tool, and it will automatically generate a visual representation of your database structure, showing all tables, columns, relationships, and cardinalities. It's perfect for:

Try it now at erdiagram.utoolab.com — no signup required, completely free, and runs entirely in your browser for maximum privacy.