How PHP Connects to MySQL
Posted: Sat Apr 25, 2026 6:42 pm
How PHP Connects to MySQL Securely (Step-by-Step)
Many dynamic websites use a database to store information such as users, posts, comments, products, settings or logs.
PHP can connect to MySQL or MariaDB and work with this data. In this guide we use PDO, because it supports prepared statements and is a good modern choice for secure PHP database access.
1. What You Need
On Debian or Ubuntu:
Restart Apache:
If you use PHP-FPM:
3. Create a Database and Limited User
Log in to MySQL or MariaDB:
Create the database:
Create a database user:
Give only the permissions needed for a normal application:
Important:
Do not use the MySQL root user for a website. A web application should only have the permissions it really needs.
4. Create a Simple Table
Log in with the new user:
Create a table:
5. Store Database Config Safely
For simple learning, you can use a config file. In production, this file should not be inside the public web directory.
Good example:
Bad example:
The public folder should contain only files that visitors are allowed to access.
6. Secure PDO Connection
Create:
Example:
Why these PDO options matter:
Example:
8. Read Data Safely
Example:
Important:
Prepared statements protect database queries. protects browser output against XSS.
You normally need both.
9. Search with Prepared Statements
Example:
10. Update Data Safely
Example:
11. Delete Data Safely
Example:
12. Important Security Notes
If your PHP script receives data from an HTML form, also think about:
14. Common Errors
Error: could not find driver
The PHP MySQL module is missing.
Error: Access denied for user
The database username, password or permissions are wrong.
Error: Unknown database
The database does not exist.
Error: Connection refused
MySQL or MariaDB may not be running.
or:
Conclusion
PHP can connect to MySQL and MariaDB securely when you use the right basics:
Many dynamic websites use a database to store information such as users, posts, comments, products, settings or logs.
PHP can connect to MySQL or MariaDB and work with this data. In this guide we use PDO, because it supports prepared statements and is a good modern choice for secure PHP database access.
1. What You Need
- A web server such as Apache or Nginx
- PHP installed
- MySQL or MariaDB installed
- The PHP MySQL module
- A database name
- A database user with limited permissions
On Debian or Ubuntu:
Code: Select all
sudo apt update
sudo apt install php-mysql
Code: Select all
sudo systemctl restart apache2
Code: Select all
sudo systemctl restart php8.4-fpm
Log in to MySQL or MariaDB:
Code: Select all
sudo mysql
Code: Select all
CREATE DATABASE testdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Code: Select all
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'CHANGE_THIS_TO_A_LONG_RANDOM_PASSWORD';
Code: Select all
GRANT SELECT, INSERT, UPDATE, DELETE ON testdb.* TO 'testuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Do not use the MySQL root user for a website. A web application should only have the permissions it really needs.
4. Create a Simple Table
Log in with the new user:
Code: Select all
mysql -u testuser -p testdb
Code: Select all
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL,
email VARCHAR(190) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
For simple learning, you can use a config file. In production, this file should not be inside the public web directory.
Good example:
Code: Select all
/var/www/example.com/config/db.php
/var/www/example.com/public/index.php
Code: Select all
/var/www/example.com/public/db.php
6. Secure PDO Connection
Create:
Code: Select all
config/db.php
Code: Select all
<?php
// Database configuration
$dbHost = 'localhost';
$dbName = 'testdb';
$dbUser = 'testuser';
$dbPass = 'CHANGE_THIS_TO_A_LONG_RANDOM_PASSWORD';
try {
// Create a secure PDO connection
$pdo = new PDO(
"mysql:host={$dbHost};dbname={$dbName};charset=utf8mb4",
$dbUser,
$dbPass,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]
);
} catch (PDOException $e) {
// Log the real error, but do not show it to visitors
error_log($e->getMessage());
http_response_code(500);
exit('Database connection failed.');
}
- ERRMODE_EXCEPTION makes errors easier to handle.
- FETCH_ASSOC returns clean associative arrays.
- ATTR_EMULATE_PREPARES false uses native prepared statements when possible.
- utf8mb4 supports full Unicode, including special characters and emojis.
Example:
Code: Select all
<?php
require_once __DIR__ . '/../config/db.php';
// Example data
$username = 'MegaTux';
$email = 'megatux@example.com';
// Insert data with a prepared statement
$stmt = $pdo->prepare(
"INSERT INTO users (username, email) VALUES (:username, :email)"
);
$stmt->execute([
':username' => $username,
':email' => $email,
]);
echo 'User inserted successfully.';
Example:
Code: Select all
<?php
require_once __DIR__ . '/../config/db.php';
// Select users
$stmt = $pdo->query(
"SELECT id, username, email, created_at FROM users ORDER BY id DESC"
);
$users = $stmt->fetchAll();
foreach ($users as $user) {
echo htmlspecialchars($user['username'], ENT_QUOTES, 'UTF-8') . ' - ';
echo htmlspecialchars($user['email'], ENT_QUOTES, 'UTF-8') . '<br>';
}
Prepared statements protect database queries.
Code: Select all
htmlspecialchars()You normally need both.
9. Search with Prepared Statements
Example:
Code: Select all
<?php
require_once __DIR__ . '/../config/db.php';
$email = 'megatux@example.com';
// Search user by email
$stmt = $pdo->prepare(
"SELECT id, username, email FROM users WHERE email = :email LIMIT 1"
);
$stmt->execute([
':email' => $email,
]);
$user = $stmt->fetch();
if ($user) {
echo 'User found: ' . htmlspecialchars($user['username'], ENT_QUOTES, 'UTF-8');
} else {
echo 'User not found.';
}
Example:
Code: Select all
<?php
require_once __DIR__ . '/../config/db.php';
$id = 1;
$newUsername = 'SuperTux';
// Update user
$stmt = $pdo->prepare(
"UPDATE users SET username = :username WHERE id = :id"
);
$stmt->execute([
':username' => $newUsername,
':id' => $id,
]);
echo 'User updated.';
Example:
Code: Select all
<?php
require_once __DIR__ . '/../config/db.php';
$id = 1;
// Delete user
$stmt = $pdo->prepare(
"DELETE FROM users WHERE id = :id"
);
$stmt->execute([
':id' => $id,
]);
echo 'User deleted.';
- Do not use the database root user for websites.
- Give the database user only the permissions needed.
- Use prepared statements for user input.
- Escape output with htmlspecialchars().
- Keep database config files outside the public web root.
- Use long random passwords for database users.
- Do not display detailed errors to visitors.
- Keep PHP, MySQL/MariaDB and your server updated.
If your PHP script receives data from an HTML form, also think about:
- Input validation
- CSRF protection
- Rate limiting
- Spam protection
- Server-side checks
14. Common Errors
Error: could not find driver
The PHP MySQL module is missing.
Code: Select all
sudo apt install php-mysql
The database username, password or permissions are wrong.
Error: Unknown database
The database does not exist.
Error: Connection refused
MySQL or MariaDB may not be running.
Code: Select all
sudo systemctl status mariadb
Code: Select all
sudo systemctl status mysql
PHP can connect to MySQL and MariaDB securely when you use the right basics:
- PDO
- Prepared statements
- Limited database users
- Escaped output
- Config files outside the public directory
- No detailed error messages for visitors