Permissions & Database
"Error establishing a database connection"
Common — usually a typo, not a real outage This WordPress-specific message (Laravel shows a different error, see below) almost always means one of the four database values is wrong, not that MySQL is actually down.
Check each value in wp-config.php against what db:add actually printed:
define('DB_NAME', 'wp_example'); // matches --name?
define('DB_USER', 'wp_example_user'); // matches --user?
define('DB_PASSWORD', 'your-password'); // matches the generated password?
define('DB_HOST', 'localhost'); // almost always 'localhost'2
3
4
Remember the password is only shown once, right when db:add runs. If it is lost, rotate the existing database user's password without deleting the database:
sudo aidipanel db:user-edit \
--site example.com \
--name wp_example_user \
--generate \
--wp-config /home/example/htdocs/example.com/wp-config.php2
3
4
5
The command prints the new password once, stores the protected phpMyAdmin credential, and updates wp-config.php after writing a backup when that path is supplied.
If all four values genuinely look correct, confirm MySQL/MariaDB is actually running:
aidipanel service:status
sudo aidipanel service:restart mariadb # or mysql, matching your install2
For Laravel, the equivalent error usually surfaces as SQLSTATE[HY000] [1045] Access denied or [2002] Connection refused in storage/logs/laravel.log — same checklist, just check .env's DB_* values instead of wp-config.php.
Upload failures
Common, especially right after a migration "Unable to create directory," failed plugin installs, or failed media uploads in WordPress almost always mean PHP (running as the site's dedicated user) doesn't have write permission on the target folder.
This happens most often right after files were uploaded via scp/root, or copied in during a migration, without the ownership fix-up step:
chown -R example:example /home/example/htdocs/example.comFor the uploads directory specifically:
chmod 755 /home/example/htdocs/example.com/wp-content/uploads/For Laravel, storage/ and bootstrap/cache/ need to be writable — see Deploy a Laravel App → Fix ownership.
Confirm which user PHP is actually running as
ps aux | grep fpm | grep exampleIf you don't see the site's dedicated user in the process list at all, PHP-FPM for that site isn't running — see Server & Gateway Errors → 502 instead, this isn't a permissions problem.
403 Forbidden
Less common Two different causes produce this, and they need opposite fixes:
1. Genuinely too-restrictive file permissions — directories need the execute bit to be listable:
find /home/example/htdocs/example.com -type d -exec chmod 755 {} \;
find /home/example/htdocs/example.com -type f -exec chmod 644 {} \;2
2. An Nginx deny rule matching a path you didn't expect. AidiPanel's default WordPress vhost explicitly blocks a few sensitive paths:
location ~ /\. { deny all; }
location ~ ^/(wp-config\.php|xmlrpc\.php)$ { deny all; }2
If you're getting a 403 on wp-config.php or a dotfile — that's intentional and correct, not a bug to fix. These paths are blocked deliberately for security; you should never need direct HTTP access to wp-config.php. If a 403 is hitting a path that should be public, check /etc/nginx/sites-available/<domain>.conf for a rule that's unexpectedly broader than intended.
Guarded delete refuses to run
Rare, and intentional If aidipanel site:delete --purge --yes --user example refuses to remove the Linux user/home directory, this is the guarded deletion safety check doing exactly its job — refusing is the correct, safe outcome, not a malfunction to work around by force.
It checks that /home/example/.aidipanel-managed:
- exists,
- is owned
root:root, - is not writable by the site user,
- and matches the domain/user the panel has on record for it.
Most common reason this fails: the marker file was deleted or edited manually at some point (directly, or as a side effect of a full directory restore from an old backup that predates the marker). If you're certain this is genuinely a site AidiPanel created and you want to remove it anyway:
# Confirm what's actually there
ls -la /home/example/.aidipanel-managed
cat /home/example/.aidipanel-managed 2>/dev/null
# If it's missing or doesn't match, the safe path is a manual, deliberate removal —
# review the site's contents first, then:
userdel -r example
rm -f /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/example.com.conf
systemctl reload nginx2
3
4
5
6
7
8
9
Only do this once you've manually confirmed the user/home genuinely belongs to a site you intend to delete — the whole point of the marker check is to prevent exactly this kind of manual override from happening by accident.
Database backup/restore
# Back up
aidipanel db:backup --name wp_example
# → /var/backups/aidipanel/wp_example-<timestamp>.sql.gz
# Restore
gunzip -c /var/backups/aidipanel/wp_example-<timestamp>.sql.gz | mysql -u wp_example_user -p wp_example2
3
4
5
6
If a restore fails with an access-denied error, confirm the user still exists and has permissions on that specific database — a db:delete/db:add cycle (see above) creates a fresh user that may not automatically match an old backup's expectations if the username changed.