MySQL Database Guide
Installation & Setup
Installation
# Ubuntu/Debian
sudo apt update
sudo apt install mysql-server
# CentOS/RHEL
sudo yum install mysql-server
# or
sudo dnf install mysql-server
# macOS
brew install mysql
# Start MySQL service
sudo systemctl start mysql
sudo systemctl enable mysql
Initial Configuration
# Secure installation
sudo mysql_secure_installation
# Connect to MySQL
mysql -u root -p
# Or with sudo
sudo mysql
User Management
Create Users
-- Create user with password
CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
-- Create user for remote access
CREATE USER 'username'@'%' IDENTIFIED BY 'password';
-- Grant privileges
GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'localhost';
GRANT SELECT, INSERT, UPDATE ON database_name.* TO 'username'@'localhost';
-- Apply changes
FLUSH PRIVILEGES;
User Operations
-- List all users
SELECT User, Host FROM mysql.user;
-- Change password
ALTER USER 'username'@'localhost' IDENTIFIED BY 'new_password';
-- Drop user
DROP USER 'username'@'localhost';
-- Show user privileges
SHOW GRANTS FOR 'username'@'localhost';
Database Operations
Database Management
-- Create database
CREATE DATABASE database_name;
CREATE DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- List databases
SHOW DATABASES;
-- Use database
USE database_name;
-- Drop database
DROP DATABASE database_name;
-- Show current database
SELECT DATABASE();
Table Operations
-- Create table
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- List tables
SHOW TABLES;
-- Describe table structure
DESCRIBE table_name;
-- or
SHOW COLUMNS FROM table_name;
-- Drop table
DROP TABLE table_name;
-- Truncate table (remove all data)
TRUNCATE TABLE table_name;
Data Manipulation
INSERT Operations
-- Insert single record
INSERT INTO users (username, email) VALUES ('john_doe', 'john@example.com');
-- Insert multiple records
INSERT INTO users (username, email) VALUES
('jane_doe', 'jane@example.com'),
('bob_smith', 'bob@example.com');
-- Insert with default values
INSERT INTO users (username, email) VALUES ('alice', 'alice@example.com');
-- Insert from another table
INSERT INTO users (username, email)
SELECT username, email FROM old_users WHERE active = 1;
SELECT Operations
-- Basic select
SELECT * FROM users;
SELECT username, email FROM users;
-- Select with conditions
SELECT * FROM users WHERE id > 5;
SELECT * FROM users WHERE username LIKE 'j%';
SELECT * FROM users WHERE created_at >= '2024-01-01';
-- Select with ordering
SELECT * FROM users ORDER BY created_at DESC;
SELECT * FROM users ORDER BY username ASC, created_at DESC;
-- Select with limit
SELECT * FROM users LIMIT 10;
SELECT * FROM users LIMIT 10 OFFSET 20; -- Skip first 20, get next 10
-- Select distinct values
SELECT DISTINCT username FROM users;
-- Select with aggregation
SELECT COUNT(*) FROM users;
SELECT COUNT(*) as total_users FROM users WHERE active = 1;
SELECT AVG(age) FROM users;
SELECT MAX(created_at), MIN(created_at) FROM users;
UPDATE Operations
-- Update single record
UPDATE users SET email = 'newemail@example.com' WHERE id = 1;
-- Update multiple records
UPDATE users SET active = 0 WHERE created_at < '2024-01-01';
-- Update with conditions
UPDATE users SET last_login = NOW() WHERE username = 'john_doe';
-- Update with JOIN
UPDATE users u
JOIN orders o ON u.id = o.user_id
SET u.total_orders = o.order_count
WHERE o.status = 'completed';
DELETE Operations
-- Delete specific records
DELETE FROM users WHERE id = 1;
DELETE FROM users WHERE created_at < '2024-01-01';
-- Delete with JOIN
DELETE u FROM users u
JOIN inactive_users i ON u.id = i.user_id
WHERE i.last_activity < DATE_SUB(NOW(), INTERVAL 1 YEAR);
Advanced Queries
JOIN Operations
-- Inner JOIN
SELECT u.username, o.order_date, o.total
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- Left JOIN
SELECT u.username, o.order_date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Right JOIN
SELECT u.username, o.order_date
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
-- Full OUTER JOIN (MySQL doesn't support, use UNION)
SELECT u.username, o.order_date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
UNION
SELECT u.username, o.order_date
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
Subqueries
-- Subquery in WHERE clause
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE total > 100);
-- Subquery in SELECT clause
SELECT username,
(SELECT COUNT(*) FROM orders WHERE user_id = users.id) as order_count
FROM users;
-- EXISTS subquery
SELECT * FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
GROUP BY and HAVING
-- Group by with aggregation
SELECT user_id, COUNT(*) as order_count, SUM(total) as total_spent
FROM orders
GROUP BY user_id;
-- Group by with HAVING
SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 5;
-- Group by multiple columns
SELECT YEAR(order_date) as year, MONTH(order_date) as month, COUNT(*) as orders
FROM orders
GROUP BY YEAR(order_date), MONTH(order_date);
Creating Indexes
-- Create index
CREATE INDEX idx_username ON users(username);
CREATE INDEX idx_email ON users(email);
-- Create unique index
CREATE UNIQUE INDEX idx_unique_email ON users(email);
-- Create composite index
CREATE INDEX idx_user_date ON orders(user_id, order_date);
-- Create full-text index
CREATE FULLTEXT INDEX idx_content ON posts(title, content);
-- Show indexes
SHOW INDEX FROM users;
Query Optimization
-- Explain query execution plan
EXPLAIN SELECT * FROM users WHERE username = 'john_doe';
-- Analyze table
ANALYZE TABLE users;
-- Optimize table
OPTIMIZE TABLE users;
-- Check table status
SHOW TABLE STATUS LIKE 'users';
Data Types
Numeric Types
-- Integer types
TINYINT -- -128 to 127
SMALLINT -- -32,768 to 32,767
MEDIUMINT -- -8,388,608 to 8,388,607
INT -- -2,147,483,648 to 2,147,483,647
BIGINT -- Large integers
-- Decimal types
DECIMAL(10,2) -- Fixed-point decimal
FLOAT -- Single-precision floating point
DOUBLE -- Double-precision floating point
String Types
-- Fixed-length strings
CHAR(10) -- Fixed 10 characters
-- Variable-length strings
VARCHAR(255) -- Variable up to 255 characters
TEXT -- Up to 65,535 characters
MEDIUMTEXT -- Up to 16,777,215 characters
LONGTEXT -- Up to 4,294,967,295 characters
-- Binary strings
BINARY(10) -- Fixed binary string
VARBINARY(255) -- Variable binary string
BLOB -- Binary large object
Date and Time Types
DATE -- YYYY-MM-DD
TIME -- HH:MM:SS
DATETIME -- YYYY-MM-DD HH:MM:SS
TIMESTAMP -- Unix timestamp
YEAR -- YYYY
Backup and Restore
Backup Operations
# Backup single database
mysqldump -u username -p database_name > backup.sql
# Backup all databases
mysqldump -u username -p --all-databases > all_databases.sql
# Backup with compression
mysqldump -u username -p database_name | gzip > backup.sql.gz
# Backup specific tables
mysqldump -u username -p database_name table1 table2 > tables_backup.sql
# Backup with specific options
mysqldump -u username -p --single-transaction --routines --triggers database_name > backup.sql
Restore Operations
# Restore from backup
mysql -u username -p database_name < backup.sql
# Restore all databases
mysql -u username -p < all_databases.sql
# Restore from compressed backup
gunzip < backup.sql.gz | mysql -u username -p database_name
Configuration and Tuning
Important Configuration Parameters
# /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
# Memory settings
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_log_buffer_size = 16M
# Connection settings
max_connections = 200
max_connect_errors = 1000
# Query cache
query_cache_size = 64M
query_cache_type = 1
# Logging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# Binary logging
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 7
-- Show process list
SHOW PROCESSLIST;
-- Show status
SHOW STATUS;
-- Show variables
SHOW VARIABLES;
-- Show engine status
SHOW ENGINE INNODB STATUS;
-- Monitor slow queries
SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10;
Security Best Practices
Security Configuration
-- Remove anonymous users
DELETE FROM mysql.user WHERE User='';
-- Remove test database
DROP DATABASE IF EXISTS test;
-- Set root password
ALTER USER 'root'@'localhost' IDENTIFIED BY 'strong_password';
-- Create application user with limited privileges
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON app_database.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
Connection Security
# Bind to specific interface
bind-address = 127.0.0.1
# Use SSL connections
ssl-ca = /path/to/ca-cert.pem
ssl-cert = /path/to/server-cert.pem
ssl-key = /path/to/server-key.pem
Common Commands Reference
System Commands
# Start/Stop/Restart MySQL
sudo systemctl start mysql
sudo systemctl stop mysql
sudo systemctl restart mysql
sudo systemctl status mysql
# Check MySQL version
mysql --version
# Connect to MySQL
mysql -u username -p -h hostname database_name
# Execute SQL file
mysql -u username -p database_name < file.sql
Useful SQL Commands
-- Show current user
SELECT USER();
-- Show current time
SELECT NOW();
-- Show MySQL version
SELECT VERSION();
-- Show current database
SELECT DATABASE();
-- Show table size
SELECT
table_name AS 'Table',
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS 'Size (MB)'
FROM information_schema.tables
WHERE table_schema = 'your_database_name'
ORDER BY (data_length + index_length) DESC;