Paramclasses Academy - Blog

Tutorials Details

PHP Login and Registration System with MySQL

PHP Login and Registration System with MySQL

October 10, 2026

Meta Description: Learn how to create a secure PHP login and registration system using MySQL, PDO, password hashing, sessions, validation, and authentication.

Focus Keyword: PHP login and registration system

Secondary Keywords: PHP login system tutorial, PHP registration form with MySQL, PHP PDO login, PHP password hashing, PHP session authentication, secure PHP login page

URL Slug: php-login-registration-system-mysql


Introduction

Welcome to Module 12 of our Core PHP tutorial series!

In Module 10, we created a Student Management System using CRUD operations. In Module 11, we improved the application by adding search, filtering, and pagination.

However, there is one important feature still missing: user authentication.

Imagine that anyone can open your Student Management System and add, edit, or delete student records without logging in. This would create a serious security problem.

To solve this issue, we need a login and registration system.

In this tutorial, we will learn how to create a PHP login and registration system using Core PHP, MySQL, PDO, password hashing, and PHP sessions.

We will implement the following features:

  • User registration with name, email, and password.

  • Secure password storage using password_hash().

  • User login using email and password.

  • Session-based authentication.

  • Protection for pages that require login.

  • Logout functionality.

  • Form validation and secure database queries.

  • Prevention of duplicate email registrations.

We will continue using the existing Student Management System wherever practical instead of creating an unrelated project from scratch.

1. What Is Authentication in PHP?

Authentication is the process of verifying a user's identity.

For example, when a user enters an email address and password, the application checks whether those credentials match a registered account.

If the credentials are valid, the application starts an authenticated session.

There are three important concepts to understand.

1.1 Registration

Registration allows a new user to create an account.

The user submits information such as a name, email address, and password. The application validates the information and stores the account in the database.

1.2 Login

Login verifies the user's credentials against the registered account.

The application should never compare passwords against plaintext passwords stored in the database. Instead, it verifies the submitted password against a secure password hash.

1.3 Session

A session allows the application to remember an authenticated user across multiple requests.

Without a session or another authentication mechanism, the application would not automatically remember that a user successfully logged in when navigating to another page.

2. Requirements for the Project

Before starting, make sure you have:

  • PHP 8.x.

  • MySQL or MariaDB.

  • XAMPP or another local PHP development environment.

  • A code editor such as Visual Studio Code.

  • The existing Student Management System from the previous modules.

Start Apache and MySQL, then open phpMyAdmin:

http://localhost/phpmyadmin/

We will continue using the existing student_db database.

Important: If your project already has a user table, inspect its structure before creating another one. Avoid duplicating tables or changing existing database structures unnecessarily.

3. Create the Users Table

We need a database table to store registered user accounts.

Execute the following SQL in the existing student_db database if an equivalent users table does not already exist.

CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Let's understand the columns.

Column Purpose
id Unique identifier for each user
name User's name
email Unique email address
password Secure password hash
created_at Account creation timestamp

The UNIQUE constraint prevents two accounts from being created with the same email address.

The password column uses VARCHAR(255) because password hashes may have different lengths depending on the algorithm and configuration.

Security note: Never store users' actual passwords in the database.

4. Understand Password Hashing in PHP

PHP provides two important functions for password security:

  • password_hash() generates a password hash.

  • password_verify() checks whether a submitted password matches that hash.

For registration, use:

$passwordHash = password_hash(
    $password,
    PASSWORD_DEFAULT
);

Store $passwordHash in the database rather than $password.

During login, verify the password:

if (password_verify($password, $user["password"])) {
    // Credentials are valid.
}

You should not attempt to decrypt a password hash. Password hashing is designed for verification, not reversible encryption.

5. Check the Existing Database Connection

Open the existing db.php file from Module 10.

Your project should already have a PDO connection. If it does, continue using that connection instead of creating another one.

A basic example looks like this:

<?php

$host = "localhost";
$dbname = "student_db";
$username = "root";
$password = "";

$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";

$pdo = new PDO(
    $dsn,
    $username,
    $password,
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false
    ]
);

These credentials are common in a default local XAMPP installation. Use your actual database credentials if they differ.

In a production environment, keep database credentials outside publicly accessible files and use an appropriately restricted database account.

6. Create the Registration Page

Create a file named register.php in your project directory.

The registration page will validate the form, hash the password, and save the user in the database.

<?php

session_start();

require_once "db.php";

$errors = [];
$name = "";
$email = "";

if ($_SERVER["REQUEST_METHOD"] === "POST") {

    $name = trim($_POST["name"] ?? "");
    $email = trim($_POST["email"] ?? "");
    $password = $_POST["password"] ?? "";
    $confirmPassword = $_POST["confirm_password"] ?? "";

    if ($name === "" || strlen($name) > 100) {
        $errors[] = "Please enter a valid name.";
    }

    if (
        !filter_var($email, FILTER_VALIDATE_EMAIL) ||
        strlen($email) > 150
    ) {
        $errors[] = "Please enter a valid email address.";
    }

    if (strlen($password) < 12) {
        $errors[] = "Password must contain at least 12 characters.";
    }

    if ($password !== $confirmPassword) {
        $errors[] = "Passwords do not match.";
    }

    if (!$errors) {

        try {

            $passwordHash = password_hash(
                $password,
                PASSWORD_DEFAULT
            );

            $stmt = $pdo->prepare(
                "INSERT INTO users (name, email, password)
                 VALUES (:name, :email, :password)"
            );

            $stmt->execute([
                "name" => $name,
                "email" => $email,
                "password" => $passwordHash
            ]);

            header("Location: login.php?registered=1");
            exit;

        } catch (PDOException $e) {

            if ($e->getCode() === "23000") {
                $errors[] =
                    "This email address may already be registered.";
            } else {
                error_log($e->getMessage());
                $errors[] =
                    "Registration failed. Please try again later.";
            }
        }
    }
}

function escapeHtml($value)
{
    return htmlspecialchars(
        (string) $value,
        ENT_QUOTES | ENT_SUBSTITUTE,
        "UTF-8"
    );
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>User Registration</title>
</head>
<body>

    <h1>Create an Account</h1>

    <?php foreach ($errors as $error): ?>
        <p><?= escapeHtml($error) ?></p>
    <?php endforeach; ?>

    <form method="POST" action="register.php">

        <label for="name">Full Name</label>
        <input
            type="text"
            id="name"
            name="name"
            maxlength="100"
            value="<?= escapeHtml($name) ?>"
            autocomplete="name"
            required
        >

        <br><br>

        <label for="email">Email Address</label>
        <input
            type="email"
            id="email"
            name="email"
            maxlength="150"
            value="<?= escapeHtml($email) ?>"
            autocomplete="email"
            required
        >

        <br><br>

        <label for="password">Password</label>
        <input
            type="password"
            id="password"
            name="password"
            autocomplete="new-password"
            required
        >

        <br><br>

        <label for="confirm_password">Confirm Password</label>
        <input
            type="password"
            id="confirm_password"
            name="confirm_password"
            autocomplete="new-password"
            required
        >

        <br><br>

        <button type="submit">Register</button>

    </form>

    <p>
        Already have an account?
        <a href="login.php">Login here</a>
    </p>

</body>
</html>

How does registration work?

  1. The user fills out the registration form.

  2. PHP validates the name, email, and password.

  3. password_hash() creates a password hash.

  4. PDO inserts the account using a prepared statement.

  5. The database's unique email constraint prevents duplicate accounts.

  6. After successful registration, the user is redirected to the login page.

In a production application, also implement CSRF protection, request throttling, appropriate session settings, and any required email verification.

7. Create the Login Page

Create login.php.

This page retrieves the account by email and verifies the submitted password.

<?php

session_start();

require_once "db.php";

$error = "";
$email = "";

if (!empty($_SESSION["user_id"])) {
    header("Location: dashboard.php");
    exit;
}

if ($_SERVER["REQUEST_METHOD"] === "POST") {

    $email = trim($_POST["email"] ?? "");
    $password = $_POST["password"] ?? "";

    if (
        filter_var($email, FILTER_VALIDATE_EMAIL) &&
        strlen($email) <= 150 &&
        $password !== ""
    ) {

        $stmt = $pdo->prepare(
            "SELECT id, name, email, password
             FROM users
             WHERE email = :email
             LIMIT 1"
        );

        $stmt->execute([
            "email" => $email
        ]);

        $user = $stmt->fetch();

        if (
            $user &&
            password_verify($password, $user["password"])
        ) {

            session_regenerate_id(true);

            $_SESSION["user_id"] = $user["id"];
            $_SESSION["user_name"] = $user["name"];

            header("Location: dashboard.php");
            exit;

        } else {
            $error = "Invalid email or password.";
        }

    } else {
        $error = "Please enter a valid email and password.";
    }
}

function escapeHtml($value)
{
    return htmlspecialchars(
        (string) $value,
        ENT_QUOTES | ENT_SUBSTITUTE,
        "UTF-8"
    );
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>User Login</title>
</head>
<body>

    <h1>Login</h1>

    <?php if (isset($_GET["registered"])): ?>
        <p>Registration successful. You can now log in.</p>
    <?php endif; ?>

    <?php if ($error !== ""): ?>
        <p><?= escapeHtml($error) ?></p>
    <?php endif; ?>

    <form method="POST" action="login.php">

        <label for="email">Email Address</label>
        <input
            type="email"
            id="email"
            name="email"
            maxlength="150"
            value="<?= escapeHtml($email) ?>"
            autocomplete="username"
            required
        >

        <br><br>

        <label for="password">Password</label>
        <input
            type="password"
            id="password"
            name="password"
            autocomplete="current-password"
            required
        >

        <br><br>

        <button type="submit">Login</button>

    </form>

    <p>
        Don't have an account?
        <a href="register.php">Register here</a>
    </p>

</body>
</html>

Important login concepts

Prepared statement: The email value is bound to a placeholder instead of being inserted directly into SQL.

Password verification: The submitted password is checked against the stored hash.

Session regeneration: session_regenerate_id(true) replaces the session ID after successful authentication, helping prevent session fixation.

Generic error message: The same invalid-credentials message is used whether the email does not exist or the password is incorrect.

For a production deployment, configure session cookies with Secure under HTTPS, HttpOnly, and an appropriate SameSite setting. Add login rate limiting and consider stronger account-recovery protections.

8. Create a Protected Dashboard

Create dashboard.php.

Only logged-in users should be able to access this page.

<?php

session_start();

if (empty($_SESSION["user_id"])) {
    header("Location: login.php");
    exit;
}

function escapeHtml($value)
{
    return htmlspecialchars(
        (string) $value,
        ENT_QUOTES | ENT_SUBSTITUTE,
        "UTF-8"
    );
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
</head>
<body>

    <h1>Welcome to Your Dashboard</h1>

    <p>
        Hello,
        <?= escapeHtml($_SESSION["user_name"] ?? "User") ?>!
    </p>

    <p>You have successfully logged in.</p>

    <a href="logout.php">Logout</a>

</body>
</html>

The important part is the session check:

if (empty($_SESSION["user_id"])) {
    header("Location: login.php");
    exit;
}

This check runs before the page outputs HTML.

If the user is not authenticated, PHP redirects them to the login page.

Remember: Hiding a link is not security. Every protected page and every protected action must enforce authentication and authorization on the server.

9. Create the Logout Page

Create logout.php.

<?php

session_start();

$_SESSION = [];

if (ini_get("session.use_cookies")) {

    $params = session_get_cookie_params();

    setcookie(
        session_name(),
        "",
        time() - 42000,
        $params["path"],
        $params["domain"],
        $params["secure"],
        $params["httponly"]
    );
}

session_destroy();

header("Location: login.php");
exit;

This code clears session data, expires the session cookie, destroys the session, and redirects the user.

In production, also ensure the session cookie settings are configured correctly before the session starts.

10. Update the Project Structure

After adding the authentication pages, the project may look like this:

student_management/
│
├── db.php
├── functions.php
├── index.php
├── create.php
├── edit.php
├── delete.php
├── register.php
├── login.php
├── dashboard.php
├── logout.php
└── style.css

The registration and login pages are new. The existing CRUD files remain in place.

However, adding a dashboard login check does not automatically protect index.php, create.php, edit.php, or delete.php.

You must apply the authentication check to every protected page and enforce appropriate authorization for every create, update, and delete operation.

If your project already has a shared authentication helper, reuse it instead of copying the same logic into every file.

11. Protect Existing Student Management Pages

For a small tutorial project, you can begin by adding the following guard to each protected PHP page before any HTML output:

<?php

session_start();

if (empty($_SESSION["user_id"])) {
    header("Location: login.php");
    exit;
}

For a cleaner project, move this logic into a shared file such as auth.php:

<?php

if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

function requireLogin()
{
    if (empty($_SESSION["user_id"])) {
        header("Location: login.php");
        exit;
    }
}

Then use it in protected pages:

<?php

require_once "auth.php";

requireLogin();

require_once "db.php";

The helper should be loaded before the page sends output.

If you use the shared helper, avoid calling session_start() a second time unnecessarily.

For applications with multiple user roles, authentication alone is not enough. For example, an ordinary staff account should not automatically receive permission to delete all student records. Role and ownership checks should be enforced separately.

12. Test the Login and Registration System

Open your local project:

http://localhost/student_management/register.php

Run the following tests.

Test Expected result
Register with valid details Account is created
Register with an existing email Duplicate account is rejected
Enter an invalid email Validation error appears
Enter different passwords Registration is rejected
Enter a password shorter than 12 characters Validation error appears
Log in with valid credentials Dashboard opens
Log in with an incorrect password Generic error appears
Open the dashboard without logging in Redirect to login
Log out Session is cleared
Open the dashboard after logout Redirect to login
Open a protected CRUD page without logging in Redirect to login

Also inspect the database after registration.

The password column should contain a password hash, not the original password.

13. Common Errors and Solutions

Error 1: Headers already sent

This occurs when PHP tries to redirect after output has already been sent.

Solution: Execute session handling and header() redirects before HTML output. Check for accidental whitespace or output before the opening PHP tag.

Error 2: Duplicate email registration

This occurs when the email address already exists in the database.

Solution: Keep the unique database constraint and handle duplicate-key exceptions appropriately.

Error 3: Login fails despite using the correct password

Possible causes: The database contains plaintext passwords, the password hash was not saved correctly, or the login query uses the wrong column.

Solution: Verify that registration stores password_hash() output and login uses password_verify().

Error 4: Session does not persist

Possible causes: Cookies are disabled, the session configuration is inconsistent, or output occurs before session initialization.

Solution: Check browser cookie settings, session configuration, and the order in which PHP initializes the session.

Error 5: Users can still open CRUD pages without logging in

Cause: The authentication check was added only to the dashboard.

Solution: Protect every relevant page and every state-changing endpoint on the server.

14. Security Best Practices

Before deploying a PHP login system publicly, remember these principles:

  • Store password hashes, never plaintext passwords.

  • Use PDO prepared statements for database queries.

  • Regenerate session IDs after authentication.

  • Use HTTPS in production.

  • Set secure session cookie options.

  • Add CSRF protection to registration and other state-changing forms.

  • Add rate limiting and monitoring to login attempts.

  • Use generic login error messages.

  • Enforce authorization on every protected action.

  • Keep database credentials and error details out of public responses.

  • Use a secure password-reset workflow if password recovery is implemented.

  • Consider email verification when appropriate for the application.

The code in this tutorial is a learning foundation. A production authentication system needs these additional protections configured and tested.

15. Practice Exercises

Beginner exercises

  1. Add a phone number field to registration.

  2. Display the user's name on the dashboard.

  3. Add a link from the login page to registration.

  4. Add a logout link to the dashboard.

  5. Create a simple CSS design for the login and registration forms.

Intermediate exercises

  1. Create a shared auth.php helper.

  2. Protect all existing student CRUD pages.

  3. Add role-based access for administrators and staff.

  4. Add server-side validation for all registration fields.

  5. Implement a password-reset flow using secure, expiring tokens.

Mini project challenge

Upgrade your Student Management System so that:

  • New users can register.

  • Registered users can log in and log out.

  • Unauthenticated visitors cannot access protected student records.

  • Only authorized users can add, edit, or delete records.

  • Passwords are stored securely.

  • Session handling is configured correctly.

  • Login and registration forms are responsive and user-friendly.

Test the application thoroughly before moving on to the next module.

16. Frequently Asked Questions (FAQs)

Q1. How do I create a login system in PHP with MySQL?

Create a users table, register users with hashed passwords, verify credentials with password_verify(), and maintain authenticated sessions to protect pages.

Q2. How do I store passwords securely in PHP?

Use password_hash() with PASSWORD_DEFAULT and store the resulting hash in the database.

Q3. What is the difference between password_hash() and password_verify()?

password_hash() generates a password hash, while password_verify() checks a submitted password against a stored hash.

Q4. What is a PHP session used for?

A PHP session allows the application to retain authentication information across multiple requests.

Q5. How do I protect a PHP page from unauthorized access?

Start or resume the session, verify that the user is authenticated, and redirect unauthenticated users before sending page output.

Q6. Why should I use PDO prepared statements?

Prepared statements separate SQL instructions from user-provided values, helping protect database queries against SQL injection.

Q7. Can I add login functionality to an existing PHP CRUD project?

Yes. You can add authentication to the existing project and protect its CRUD pages without rebuilding the entire application.

Q8. Is a login system secure just because it uses password hashing?

No. Secure authentication also requires session protection, access control, input validation, CSRF protection, rate limiting, and secure deployment settings.

Conclusion

In this module, we learned how to create a PHP login and registration system using Core PHP, MySQL, PDO, password hashing, and sessions.

We implemented user registration, login, a protected dashboard, logout functionality, and basic authentication checks.

These features provide the foundation for building more secure database-driven applications.

In the next module, we will learn how to implement PHP User Roles and Permissions, so that administrators and ordinary users can access only the features they are authorized to use.