A manual phpMyAdmin deployment combines a replaceable application tree with a small amount of site-specific configuration. Extracting a new release over the live directory can leave obsolete files behind, while a side-by-side tree keeps the existing release available during the change.
This method targets an archive-based installation served by Apache 2.4 with PHP loaded as its in-process module at /var/www/html/phpmyadmin. It copies only config.inc.php into the fresh tree; distribution-managed packages, PHP-FPM deployments, custom themes, authentication extensions, and other locally modified PHP files require their own upgrade path.
Keep the staged, live, and pre-upgrade trees on the same filesystem so each directory rename remains atomic. The previous tree stays outside the web document root as the recovery boundary until the upgraded login and SQL query both work.
$ sudo php -r '$package = json_decode(file_get_contents("/var/www/html/phpmyadmin/composer.json"), true); echo $package["version"], PHP_EOL;'
5.2.2
$ sudo apachectl -M Loaded Modules: ##### snipped ##### php_module (shared) ##### snipped #####
PHP-FPM deployments need a separate service-reload and opcode-cache plan.
$ PMA_OLD_VERSION=5.2.2
$ PMA_VERSION=5.2.3
$ PMA_URL="http://127.0.0.1/phpmyadmin/"
The local request checks the replacement tree through Apache; the later browser steps check the normal authenticated route.
$ PMA_STAGED="/var/www/phpMyAdmin-${PMA_VERSION}-all-languages"
$ PMA_ROLLBACK="/var/www/phpmyadmin-before-${PMA_OLD_VERSION}"
$ cd /tmp
$ curl -fsSLO "https://files.phpmyadmin.net/phpMyAdmin/${PMA_VERSION}/phpMyAdmin-${PMA_VERSION}-all-languages.tar.xz"
$ curl -fsSLO "https://files.phpmyadmin.net/phpMyAdmin/${PMA_VERSION}/phpMyAdmin-${PMA_VERSION}-all-languages.tar.xz.sha256"
$ sha256sum --check "phpMyAdmin-${PMA_VERSION}-all-languages.tar.xz.sha256"
phpMyAdmin-5.2.3-all-languages.tar.xz: OK
$ sudo test ! -e "$PMA_STAGED"
A nonzero exit means extraction would merge with a leftover tree; stop and investigate that path instead of deleting unknown contents.
$ sudo tar --extract --file="/tmp/phpMyAdmin-${PMA_VERSION}-all-languages.tar.xz" --directory=/var/www
Never extract a new phpMyAdmin release over the active tree because obsolete files can remain reachable.
$ sudo cp --preserve=mode,ownership /var/www/html/phpmyadmin/config.inc.php "$PMA_STAGED/config.inc.php"
$ sudo php -l "$PMA_STAGED/config.inc.php" No syntax errors detected in /var/www/phpMyAdmin-5.2.3-all-languages/config.inc.php
$ sudo sha256sum /var/www/html/phpmyadmin/config.inc.php "$PMA_STAGED/config.inc.php"
Both output lines must show the same SHA-256 digest before the directory switch.
$ df -P /var/www/html/phpmyadmin "$PMA_STAGED"
Both rows must report the same filesystem device because cross-filesystem moves are not atomic.
$ sudo test ! -e "$PMA_ROLLBACK"
A nonzero exit means the recovery name collides with existing state; stop instead of replacing or deleting that tree.

phpMyAdmin becomes unavailable until the staged tree reaches the live path. The untouched old tree at $PMA_ROLLBACK is the recovery boundary throughout the maintenance check.
$ sudo mv --no-clobber --no-target-directory /var/www/html/phpmyadmin "$PMA_ROLLBACK"
$ sudo mv --no-clobber --no-target-directory "$PMA_STAGED" /var/www/html/phpmyadmin
$ sudo apachectl -k graceful
In-flight requests can finish in the previous Apache generation while replacement processes start, so keep the maintenance window active.
$ sudo php -r '$package = json_decode(file_get_contents($argv[1] . "/composer.json"), true); echo $package["version"], PHP_EOL;' "$PMA_ROLLBACK" 5.2.2
$ sudo php -r '$package = json_decode(file_get_contents("/var/www/html/phpmyadmin/composer.json"), true); echo $package["version"], PHP_EOL;'
5.2.3
$ curl -fsSI "$PMA_URL" HTTP/1.1 200 OK ##### snipped ##### Content-Type: text/html; charset=utf-8
$ rm -- "/tmp/phpMyAdmin-${PMA_VERSION}-all-languages.tar.xz"
$ rm -- "/tmp/phpMyAdmin-${PMA_VERSION}-all-languages.tar.xz.sha256"








