Almost every dynamic web application needs some way to identify who's using it, and that starts with a login system. In this tutorial you will build a simple but secure PHP and MySQLi login system from scratch, covering user registration, password hashing, session based login, and a protected page that only logged in users can access.
By the end you'll have a working authentication flow you can build on for any future project.
What You Will Need
- A local server environment such as XAMPP, WAMP or MAMP (PHP 7.4 or higher recommended)
- MySQL or MariaDB
- A code editor such as VS Code
- Basic familiarity with PHP and HTML forms
Step 1: Create the Database and Users Table
Open phpMyAdmin or your MySQL client and run the following SQL to set up the database and the table that will store user accounts.
CREATE DATABASE IF NOT EXISTS login_system;
USE login_system;
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(150) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Notice we store password_hash rather than the raw password. You should never store plain text passwords in a database, ever.
Step 2: Set Up the Database Connection
Create a file called db.php. This will be included on every page that needs database access.
<?php
$host = "localhost";
$username = "root";
$password = "";
$database = "login_system";
$conn = mysqli_connect($host, $username, $password, $database);
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
?>Step 3: Build the Registration Page
Create a file called register.php. This page collects a username, email and password, hashes the password securely, then saves the new account.
<?php
include 'db.php';
$error = "";
$success = "";
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = $_POST['password'];
if (strlen($password) < 6) {
$error = "Password must be at least 6 characters long.";
} else {
$password_hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = mysqli_prepare($conn, "INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)");
mysqli_stmt_bind_param($stmt, "sss", $username, $email, $password_hash);
if (mysqli_stmt_execute($stmt)) {
$success = "Account created successfully. You can now log in.";
} else {
$error = "Username or email already exists.";
}
mysqli_stmt_close($stmt);
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Register</title>
</head>
<body>
<h2>Create an Account</h2>
<?php if ($error): ?>
<p style="color:red;"><?= htmlspecialchars($error) ?></p>
<?php endif; ?>
<?php if ($success): ?>
<p style="color:green;"><?= htmlspecialchars($success) ?></p>
<?php endif; ?>
<form method="POST" action="">
<label>Username</label><br>
<input type="text" name="username" required><br><br>
<label>Email</label><br>
<input type="email" name="email" required><br><br>
<label>Password</label><br>
<input type="password" name="password" required><br><br>
<button type="submit">Register</button>
</form>
<p>Already have an account? <a href="login.php">Log in</a></p>
</body>
</html>The password_hash() function automatically applies a strong, salted hashing algorithm, so you never have to build your own encryption logic.
Step 4: Build the Login Page
Create a file called login.php. This page checks the submitted credentials against the database and starts a session if they match.
<?php
session_start();
include 'db.php';
$error = "";
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$password = $_POST['password'];
$stmt = mysqli_prepare($conn, "SELECT id, username, password_hash FROM users WHERE username = ?");
mysqli_stmt_bind_param($stmt, "s", $username);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$user = mysqli_fetch_assoc($result);
if ($user && password_verify($password, $user['password_hash'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
header("Location: dashboard.php");
exit;
} else {
$error = "Invalid username or password.";
}
mysqli_stmt_close($stmt);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h2>Log In</h2>
<?php if ($error): ?>
<p style="color:red;"><?= htmlspecialchars($error) ?></p>
<?php endif; ?>
<form method="POST" action="">
<label>Username</label><br>
<input type="text" name="username" required><br><br>
<label>Password</label><br>
<input type="password" name="password" required><br><br>
<button type="submit">Log In</button>
</form>
<p>Don't have an account? <a href="register.php">Register</a></p>
</body>
</html>password_verify() compares the submitted password against the stored hash without ever needing to decrypt anything, since password hashes are designed to be one way.
Step 5: Protect a Page With Session Checks
Create a file called auth_check.php. Including this at the top of any page will redirect anyone who isn't logged in back to the login page.
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit;
}
?>Step 6: Build the Dashboard Page
Create a file called dashboard.php. This is the protected page only logged in users can see.
<?php
include 'auth_check.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dashboard</title>
</head>
<body>
<h2>Welcome, <?= htmlspecialchars($_SESSION['username']) ?>!</h2>
<p>You are logged in.</p>
<a href="logout.php">Log Out</a>
</body>
</html>Step 7: Build the Logout Page
Create a file called logout.php to end the session and send the user back to the login page.
<?php
session_start();
session_unset();
session_destroy();
header("Location: login.php");
exit;
?>Step 8: Test Your Login System
- Save all files inside a single folder in your server's root directory (for example
htdocs/login_system). - Start Apache and MySQL from your local server control panel.
- Visit
http://localhost/login_system/register.phpand create a new account. - Log in with those credentials at
login.phpand confirm you land ondashboard.php. - Click log out and confirm you're redirected back to the login page, and that visiting
dashboard.phpdirectly now redirects you too.
Best Practices to Keep in Mind
- Always hash passwords with
password_hash()and verify them withpassword_verify(), never store or compare plain text passwords. - Use prepared statements for every query that includes user input.
- Call
session_start()at the very top of every page that reads or writes session data. - Regenerate the session ID after a successful login with
session_regenerate_id()to help prevent session fixation attacks. - Add rate limiting or a short delay on repeated failed login attempts to slow down brute force attacks.
- Serve your app over HTTPS in production so session cookies and credentials aren't sent in plain text.
Conclusion
You've now built a complete PHP and MySQLi login system covering registration, secure password hashing, session based login, route protection and logout. This same foundation, a users table, a registration form, a login form and a session check, is the starting point for almost any application that needs user accounts, from simple dashboards to full scale platforms.
From here, consider extending it with features like email verification, password reset via email, "remember me" functionality, or role based access control for admin versus regular users.
Hit me with a comment!