Skip to content
MySQL Explained — Beginner's Guide with Examples

MySQL Explained — Beginner's Guide with Examples

DodaTech Updated Jun 6, 2026 11 min read

MySQL is the world’s most popular open-source relational database management system, known for its reliability, performance, and ease of use in powering dynamic websites and applications.

What You’ll Learn

By the end of this tutorial, you’ll install MySQL, create databases and tables with proper indexes, write JOIN queries across multiple tables, and understand MySQL-specific features like AUTO_INCREMENT and storage engines.

Why MySQL Matters

MySQL powers some of the largest websites in the world — Facebook, YouTube, Twitter (X), and WordPress (which runs over 40% of the web). At DodaTech, Doda Browser’s sync service and bookmark storage use MySQL, while Durga Antivirus Pro relies on MySQL for its threat signature database. Learning MySQL gives you a skill used by virtually every tech company.

MySQL Learning Path

    flowchart LR
  A[SQL Basics] --> B[MySQL]
  B --> C[PostgreSQL]
  C --> D[MongoDB]
  D --> E[Redis]
  E --> F[Database Design]
  B --> G{You Are Here}
  style G fill:#f90,color:#fff
  
Prerequisites: SQL basics (SELECT, INSERT, UPDATE, DELETE). Familiarity with Linux command line helps for installation but isn’t required.

What Is MySQL? (The “Why” First)

Think of MySQL as a highly organized digital warehouse. SQL is the language you use to tell the warehouse workers what to do. MySQL is the warehouse itself — it stores the data, manages access, optimizes searches, and keeps everything running smoothly even when millions of people are requesting data at the same time.

MySQL vs Other Databases

FeatureMySQLPostgreSQLSQLite
TypeClient-serverClient-serverEmbedded
ConcurrencyExcellentExcellentSingle-writer
PerformanceFast readsFeature-richLightweight
ReplicationBuilt-in (native)Built-inNone
Use caseWeb apps, CMSAnalytics, GISMobile, embedded

Installing MySQL

On Ubuntu/Debian

# Install MySQL server
sudo apt update
sudo apt install mysql-server -y

# Start the service
sudo systemctl start mysql
sudo systemctl enable mysql

# Secure the installation
sudo mysql_secure_installation
# Follow prompts: set root password, remove anonymous users,
# disable remote root login, remove test database

On macOS (Homebrew)

brew install mysql
brew services start mysql
mysql_secure_installation

Verify Installation

mysql --version
# Expected: mysql  Ver 8.0.x for Linux on x86_64

# Log in as root
sudo mysql -u root -p

Creating a Database and User

-- Create a database for our application
CREATE DATABASE shop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Create a user and grant permissions
CREATE USER 'shop_user'@'localhost' IDENTIFIED BY 'secure_password_123';
GRANT ALL PRIVILEGES ON shop.* TO 'shop_user'@'localhost';
FLUSH PRIVILEGES;

-- Use the database
USE shop;

Line-by-line explanation:

  • CHARACTER SET utf8mb4 — supports emoji and international characters
  • COLLATE utf8mb4_unicode_ci — case-insensitive comparison rules
  • CREATE USER — creates a database user (never use root for applications)
  • GRANT ALL PRIVILEGES — gives the user full access to the shop database only
  • FLUSH PRIVILEGES — reloads the permission tables

Creating Tables with MySQL Features

-- Create a customers table with MySQL-specific features
CREATE TABLE customers (
    customer_id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    phone VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    status ENUM('active', 'inactive', 'suspended') DEFAULT 'active'
) ENGINE=InnoDB;

-- Create an orders table with foreign key
CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    customer_id INT NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    total_amount DECIMAL(10, 2) NOT NULL,
    status ENUM('pending', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
        ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB;

-- Create order_items table
CREATE TABLE order_items (
    item_id INT AUTO_INCREMENT PRIMARY KEY,
    order_id INT NOT NULL,
    product_name VARCHAR(200) NOT NULL,
    quantity INT NOT NULL,
    unit_price DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(order_id)
        ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;

MySQL-Specific Features Used:

  • AUTO_INCREMENT — automatically generates sequential IDs (no need to specify them)
  • ENUM — restricts a column to specific values
  • ENGINE=InnoDB — the default storage engine, supports transactions and foreign keys
  • ON DELETE RESTRICT — prevents deleting a customer who has orders
  • ON DELETE CASCADE — when an order is deleted, its items are also deleted
  • ON UPDATE CURRENT_TIMESTAMP — automatically updates the timestamp when a row changes

Why InnoDB?

MySQL supports multiple storage engines:

EngineTransactionsForeign KeysFull-Text SearchUse Case
InnoDBYesYesYes (8.0+)General purpose
MyISAMNoNoYesRead-heavy, legacy
MemoryNoNoNoTemporary data, caching
CSVNoNoNoData exchange

Always use InnoDB for production applications. It’s the default since MySQL 5.5+.

Inserting Sample Data

-- Insert customers
INSERT INTO customers (first_name, last_name, email, phone) VALUES
    ('Alice', 'Johnson', 'alice@example.com', '555-0101'),
    ('Bob', 'Smith', 'bob@example.com', '555-0102'),
    ('Charlie', 'Brown', 'charlie@example.com', '555-0103'),
    ('Diana', 'Prince', 'diana@example.com', '555-0104');

-- Insert orders
INSERT INTO orders (customer_id, total_amount) VALUES
    (1, 150.00),
    (1, 75.50),
    (2, 200.00),
    (3, 45.99);

-- Insert order items
INSERT INTO order_items (order_id, product_name, quantity, unit_price) VALUES
    (1, 'Wireless Mouse', 2, 25.00),
    (1, 'USB-C Hub', 1, 100.00),
    (2, 'Notebook Set', 5, 15.10),
    (3, 'Monitor Stand', 1, 200.00),
    (4, 'Desk Lamp', 1, 45.99);

JOIN Queries — Connecting Tables

JOINs are where SQL becomes powerful. They let you combine data from multiple tables based on relationships.

INNER JOIN — Only Matching Records

-- Get all orders with customer information
SELECT
    o.order_id,
    c.first_name,
    c.last_name,
    o.order_date,
    o.total_amount,
    o.status
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
ORDER BY o.order_date DESC;

Output:

order_id | first_name | last_name | order_date           | total_amount | status
4        | Charlie    | Brown     | 2026-06-06 10:00:04  | 45.99        | pending
3        | Bob        | Smith     | 2026-06-06 10:00:03  | 200.00       | pending
2        | Alice      | Johnson   | 2026-06-06 10:00:02  | 75.50        | pending
1        | Alice      | Johnson   | 2026-06-06 10:00:01  | 150.00       | pending

LEFT JOIN — All Records from Left Table

-- Show all customers, even those without orders
SELECT
    c.first_name,
    c.last_name,
    COUNT(o.order_id) AS order_count,
    COALESCE(SUM(o.total_amount), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id
ORDER BY total_spent DESC;

Output:

first_name | last_name | order_count | total_spent
Alice      | Johnson   | 2           | 225.50
Bob        | Smith     | 1           | 200.00
Charlie    | Brown     | 1           | 45.99
Diana      | Prince    | 0           | 0.00

Multi-Table JOIN with Aggregation

-- Detailed order breakdown with items
SELECT
    o.order_id,
    c.first_name,
    c.last_name,
    oi.product_name,
    oi.quantity,
    oi.unit_price,
    (oi.quantity * oi.unit_price) AS line_total
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
ORDER BY o.order_id, oi.product_name;

Output:

order_id | first_name | last_name | product_name  | quantity | unit_price | line_total
1        | Alice      | Johnson   | USB-C Hub     | 1        | 100.00     | 100.00
1        | Alice      | Johnson   | Wireless Mouse| 2        | 25.00      | 50.00
2        | Alice      | Johnson   | Notebook Set  | 5        | 15.10      | 75.50
3        | Bob        | Smith     | Monitor Stand | 1        | 200.00     | 200.00
4        | Charlie    | Brown     | Desk Lamp     | 1        | 45.99      | 45.99

Indexes — Speeding Up Queries

An index is like a book’s index — it helps MySQL find data without scanning every row.

-- See how MySQL executes a query (before index)
EXPLAIN SELECT * FROM orders WHERE customer_id = 1;
-- type: ALL (full table scan — slow!)

-- Create an index on customer_id
CREATE INDEX idx_orders_customer ON orders(customer_id);

-- Now check again
EXPLAIN SELECT * FROM orders WHERE customer_id = 1;
-- type: ref (using index — fast!)

When to Use Indexes

-- Index columns used in WHERE, JOIN, and ORDER BY
CREATE INDEX idx_customers_email ON customers(email);
CREATE INDEX idx_orders_date ON orders(order_date);
CREATE INDEX idx_customers_name ON customers(last_name, first_name);

-- Unique indexes for columns that must be unique
CREATE UNIQUE INDEX idx_customers_email_unique ON customers(email);

Index Guidelines:

  • Index columns used in WHERE, JOIN, and ORDER BY
  • Don’t index every column (indexes slow down writes)
  • Use composite indexes for queries filtering multiple columns
  • Monitor slow queries with SHOW FULL PROCESSLIST and EXPLAIN

Common MySQL Mistakes

1. Not Using AUTO_INCREMENT Properly

Let MySQL handle ID generation automatically. Never manually insert IDs unless you have a very good reason.

2. Forgetting Foreign Key Constraints

Without foreign keys, you can have “orphan” records — orders referencing customers that don’t exist. Always define foreign keys for related data.

3. Using MyISAM Instead of InnoDB

MyISAM doesn’t support transactions or foreign keys. Unless you have a specific reason (full-text search on MySQL 5.6 or older), use InnoDB.

4. Not Using Prepared Statements in Applications

Always use parameterized queries in your code to prevent SQL Injection. Never concatenate user input into SQL strings.

# CORRECT (Python/MySQL)
cursor.execute("SELECT * FROM users WHERE email = %s", (user_email,))

# WRONG — SQL injection risk!
cursor.execute(f"SELECT * FROM users WHERE email = '{user_email}'")

5. Ignoring Query Performance

Use EXPLAIN to check how MySQL executes queries. A full table scan on a table with millions of rows will be painfully slow.

6. Not Backing Up Regularly

# Backup MySQL database
mysqldump -u root -p shop > shop_backup.sql

# Restore from backup
mysql -u root -p shop < shop_backup.sql

7. Using Default MySQL Port (3306) Without Firewall Rules

If MySQL must be accessible over the network, restrict access by IP and use strong passwords. Never expose MySQL directly to the internet.

Common Mistakes Beginners Make

1. Skipping the Fundamentals

Many beginners jump straight to advanced topics without mastering the basics. Take time to understand the core concepts before moving on.

2. Not Practicing Enough

Reading tutorials without writing code leads to shallow understanding. Code along with every example and experiment on your own.

3. Ignoring Error Messages

Error messages tell you exactly what went wrong. Read them carefully — they usually point to the line and type of issue.

4. Copy-Pasting Without Understanding

It’s tempting to copy code from tutorials, but typing it yourself and understanding each line builds real skill.

5. Giving Up Too Early

Every developer hits frustrating bugs. Take breaks, ask for help, and remember that struggling is part of learning.

Practice Questions

1. What is AUTO_INCREMENT in MySQL?

A feature that automatically generates sequential integer values for a column, typically used for primary keys. You don’t need to specify the value when inserting.

2. What’s the difference between InnoDB and MyISAM?

InnoDB supports transactions, foreign keys, and row-level locking. MyISAM supports table-level locking only, no transactions, no foreign keys. InnoDB is the default and recommended engine.

3. Why use indexes in MySQL?

Indexes speed up data retrieval by creating a data structure that allows the database to find rows without scanning the entire table. They’re essential for performance on large datasets.

4. What does ON DELETE CASCADE do?

When a parent record is deleted, all related child records are automatically deleted too. For example, deleting an order also deletes its order items.

5. Challenge: Write a query that finds the top-spending customer.

SELECT
    c.first_name,
    c.last_name,
    SUM(o.total_amount) AS total_spent
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id
ORDER BY total_spent DESC
LIMIT 1;

Real-World Task: Design an E-Commerce Schema

Create a complete schema for a small e-commerce application:

-- Create database
CREATE DATABASE ecommerce CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE ecommerce;

-- Products table
CREATE TABLE products (
    product_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(200) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL,
    stock_quantity INT NOT NULL DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_products_price (price),
    INDEX idx_products_name (name)
) ENGINE=InnoDB;

-- Cart table
CREATE TABLE cart (
    cart_id INT AUTO_INCREMENT PRIMARY KEY,
    customer_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT NOT NULL DEFAULT 1,
    added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id) ON DELETE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE,
    INDEX idx_cart_customer (customer_id)
) ENGINE=InnoDB;

-- Insert sample products
INSERT INTO products (name, description, price, stock_quantity) VALUES
    ('Ergonomic Keyboard', 'Mechanical keyboard with wrist rest', 89.99, 50),
    ('HD Webcam', '1080p webcam with built-in microphone', 59.99, 30),
    ('Laptop Stand', 'Adjustable aluminum laptop stand', 34.99, 100),
    ('Noise-Canceling Headphones', 'Wireless over-ear headphones', 199.99, 25);

FAQ

What is the default MySQL port?
Port 3306. Change it in /etc/mysql/mysql.conf.d/mysqld.cnf for security through obscurity, but always combine with firewall rules.
How do I reset the MySQL root password?
Stop MySQL, start with --skip-grant-tables, log in without password, UPDATE mysql.user SET authentication_string='' WHERE User='root', then restart normally and set a new password.
What is the difference between CHAR and VARCHAR?
CHAR has a fixed length (padded with spaces). VARCHAR has a variable length (only uses space needed). VARCHAR is more space-efficient for variable-length data like names and emails.
What is a storage engine?
A storage engine determines how MySQL stores, indexes, and manages data in tables. InnoDB (default) supports transactions and foreign keys. MyISAM is simpler but lacks these features.
How do I monitor MySQL performance?
Use SHOW FULL PROCESSLIST (running queries), EXPLAIN (query execution plan), SHOW STATUS (server statistics), and slow_query_log (queries exceeding a time threshold).

Try It Yourself

Create the e-commerce schema above and run these analytical queries:

-- Which products are low in stock?
SELECT name, stock_quantity
FROM products
WHERE stock_quantity < 50
ORDER BY stock_quantity;

-- What customer has the most expensive cart?
SELECT c.first_name, c.last_name, SUM(p.price * cart.quantity) AS cart_total
FROM cart
INNER JOIN customers c ON cart.customer_id = c.customer_id
INNER JOIN products p ON cart.product_id = p.product_id
GROUP BY cart.customer_id
ORDER BY cart_total DESC
LIMIT 1;

These query patterns are used by DodaZIP’s cloud storage for listing files, and by Durga Antivirus Pro for querying its threat signature database.

What’s Next

What’s Next

Congratulations on completing this Mysql tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro