VMHeaven

Guides

Install phpMyAdmin on Ubuntu and Debian — and lock it down

Install phpMyAdmin with MySQL or MariaDB on Ubuntu 22.04/24.04 and Debian 12/13, under Apache or nginx, then keep it off the public internet.

Updated 19 Sept 2026~7 min read

phpMyAdmin is the web interface most people reach for to manage MySQL or MariaDB. Ubuntu and Debian both package it, and the packaged version is the one to use. It gets security updates through apt, so you never have to remember to patch it. This guide installs it on Ubuntu 22.04/24.04 and Debian 12/13, with Apache or nginx, and then covers the part most guides skip: keeping it away from the bots that scan every IP for /phpmyadmin.

Before you start

  • A server running Ubuntu or Debian, and a user with sudo.
  • Port 80 (and 443 for HTTPS) open in your firewall.
  • On Ubuntu, the universe component enabled. It is on standard images; on minimal ones, run sudo add-apt-repository universe. If that command is missing, see add-apt-repository: command not found.

Install with Apache

  1. 1Update the system
    Ubuntu · Debian
    sudo apt update && sudo apt upgrade -y
  2. 2Install the database server

    Debian does not ship Oracle MySQL; its database server is MariaDB. Ubuntu offers both. phpMyAdmin works the same with either.

    database
    # Ubuntu, MySQL
    sudo apt install -y mysql-server
    sudo mysql_secure_installation
    
    # Debian or Ubuntu, MariaDB
    sudo apt install -y mariadb-server
    sudo mariadb-secure-installation

    Say yes to removing anonymous users, disallowing remote root login and dropping the test database. On Ubuntu’s MySQL, root logs in through the OS account (auth_socket) rather than a password, so the script may skip the root password step. That is fine — leave it that way.

  3. 3Install phpMyAdmin
    Ubuntu · Debian
    sudo apt install -y phpmyadmin

    If no web server is installed yet, this pulls in Apache and PHP automatically. The installer then asks two questions:

    • Web server to reconfigure automatically — press Space to mark apache2 (an asterisk appears), then Enter. Pressing Enter without Space selects nothing, and that is the number-one reason for a 404 later.
    • Configure database for phpmyadmin with dbconfig-common? — Yes. It asks for a password for phpMyAdmin’s internal user; leave it blank to generate a random one.
  4. 4Check it loads

    Open http://YOUR_SERVER_IP/phpmyadmin. You should see the login page. Do not log in over plain HTTP from a café, and do not leave it like this — the lock-down section below is part of the install, not an optional extra.

Create a user to log in with

Logging in as root fails with #1698 - Access denied for user ‘root’@‘localhost’. That is the socket authentication from step 2 working as intended. Do not weaken root. Create a separate admin account instead:

open the SQL shell
sudo mysql        # or: sudo mariadb
SQL
CREATE USER 'dbadmin'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON *.* TO 'dbadmin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Log in to phpMyAdmin as dbadmin. For everyday work on a single application, a user limited to that application’s database is safer still. Resist switching root to mysql_native_password, as older guides suggest: MySQL 8.4 disables that plugin by default. The background is in MySQL Access denied for root@localhost.

Lock it down

Bots request /phpmyadmin on every IP address they find, and they try passwords there. Pick at least one of the following. The first is the strongest.

All Apache changes go into the <Directory /usr/share/phpmyadmin> block of /etc/phpmyadmin/apache.conf. On Ubuntu, /etc/apache2/conf-available/phpmyadmin.conf is a link to the same file.

Option A: reachable only through SSH

/etc/phpmyadmin/apache.conf — inside the Directory block
Require local
on your computer
ssh -N -L 8080:127.0.0.1:80 user@YOUR_SERVER_IP
# then open http://localhost:8080/phpmyadmin

phpMyAdmin now answers only requests that come from the server itself. The SSH tunnel makes your browser one of them. Nothing is exposed, and no certificate is needed.

Option B: only from your IP address

inside the Directory block
Require ip 198.51.100.7

Option C: a second password, over HTTPS

create the password file
sudo htpasswd -c /etc/apache2/.htpasswd yourname
inside the Directory block
AuthType Basic
AuthName "Restricted"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user

Basic auth sends the password with every request, so only use it over HTTPS. Point a (sub)domain at the server — see pointing a domain at your VPS — and get a free certificate:

HTTPS
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d db.example.com

Also worth it: a different URL

Change Alias /phpmyadmin /usr/share/phpmyadmin at the top of the same file to something like Alias /db-7f3k /usr/share/phpmyadmin. That is not security on its own, but it removes you from the scripted scans. Apply any of these changes with:

apply
sudo apache2ctl configtest && sudo systemctl reload apache2

Install with nginx instead

Install nginx and PHP-FPM first. With a web server and PHP-FPM already present, installing phpMyAdmin does not pull in Apache.

Ubuntu · Debian
sudo apt install -y nginx php-fpm
sudo apt install -y phpmyadmin

When the installer asks which web server to configure, select neither and press Enter. Answer Yes to dbconfig-common as before. Then check that apt did not install apache2 after all (dpkg -l apache2). If it did, remove it, because it will fight nginx for port 80.

The PHP-FPM socket name includes the PHP version: ls /run/php/ shows it. It is php8.1 on Ubuntu 22.04, php8.3 on 24.04, php8.2 on Debian 12 and php8.4 on Debian 13.

/etc/nginx/sites-available/phpmyadmin
server {
    listen 80;
    server_name db.example.com;

    root /usr/share/phpmyadmin;
    index index.php;

    # only your address
    allow 198.51.100.7;
    deny all;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ ^/(libraries|templates|setup/lib)/ {
        deny all;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
}
enable
sudo ln -s /etc/nginx/sites-available/phpmyadmin /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
# HTTPS: sudo apt install -y python3-certbot-nginx && sudo certbot --nginx -d db.example.com

Troubleshooting

  • 404 Not Found at /phpmyadmin (Apache). The web server was not selected during install. Run sudo a2enconf phpmyadmin && sudo systemctl reload apache2, or run the dialog again with sudo dpkg-reconfigure phpmyadmin.
  • The browser shows PHP source code or downloads a file. Apache is not running PHP. Install libapache2-mod-php and restart Apache.
  • ERROR 1819: Your password does not satisfy the current policy. The MySQL password validation component rejected the password during install. Choose retry and enter a longer password with mixed characters, or leave it blank to get a random one.
  • Imports fail with a file-size error. Raise upload_max_filesize and post_max_size in the PHP ini your server uses (/etc/php/8.x/apache2/php.ini or /etc/php/8.x/fpm/php.ini), then restart Apache or PHP-FPM. For really large dumps, import on the shell with mysql dbname < dump.sql instead.

Rather not maintain a database panel at all? VMHeaven’s Plesk and cPanel hosting plans include phpMyAdmin, kept up to date for you. On your own VPS, the steps above get you the same thing in about ten minutes.

Frequently asked

Why can't I log in to phpMyAdmin as root?

On Ubuntu and Debian, the database root user authenticates through the OS account (auth_socket / unix_socket), not a password. Create a separate admin user with a password and log in with that.

Why does /phpmyadmin return 404 after installing?

The web server was not selected in the installer — it needs Space, then Enter. Run 'sudo a2enconf phpmyadmin && sudo systemctl reload apache2', or 'sudo dpkg-reconfigure phpmyadmin'.

What is the safest way to expose phpMyAdmin?

Not at all: restrict it to 'Require local' and reach it through an SSH tunnel. If it must be public, limit it to your IP or add HTTP basic auth over HTTPS.

More in Guides

See all