PHP 8.5 shipped on November 20, 2025, and it’s the most significant PHP release in the 8.x series. The pipe operator, first-class URI handling, built-in array_first() and array_last(), and OPcache compiled in as standard — not optional — are headline changes. But the clearest reason to upgrade now is simpler: PHP 8.1 reached end of active support in November 2024 and PHP 8.2 follows in December 2025. Running unsupported PHP on a live site means unpatched security vulnerabilities, and that risk compounds daily.
This guide covers the complete upgrade process on Ubuntu 24.04 (Noble Numbat) and Ubuntu 22.04 (Jammy Jellyfish): fresh installs, in-place upgrades from PHP 7.x, 8.0, 8.1, 8.2, 8.3, or 8.4, Apache and Nginx paths, extension reinstallation, and the errors that catch people out the most.
PHP Version Support Timeline
Before upgrading, understand what you’re leaving and what you’re gaining:
| Version | Active Support Until | Security Support Until | Status |
|---|---|---|---|
| PHP 7.4 | Nov 2022 | Nov 2022 | EOL — vulnerable |
| PHP 8.0 | Nov 2023 | Nov 2023 | EOL — vulnerable |
| PHP 8.1 | Nov 2024 | Dec 2025 | Security-only → EOL |
| PHP 8.2 | Dec 2024 | Dec 2026 | Security-only |
| PHP 8.3 | Nov 2025 | Nov 2027 | Active |
| PHP 8.4 | Nov 2026 | Nov 2028 | Active |
| PHP 8.5 | Nov 2027 | Nov 2029 | Active — latest |
Running any PHP version with EOL or security-only status on a public-facing site is a meaningful risk. For the broader context on keeping a WordPress site protected, see the WordPress security hardening guide.
What’s New in PHP 8.5
1. Pipe Operator (|>)
Chains function calls left-to-right without nesting. Replaces deeply nested function calls with a readable linear flow.
$result = " hello world "
|> trim(...)
|> strtoupper(...)
|> str_word_count(...);
// Result: 2
2. URI Extension
PHP 8.5 introduces Uri\Rfc3986\Uri (RFC 3986 compliant) and Uri\WhatWg\Url (browser-style URL parsing) as first-class language features — no more parse_url() edge cases.
$uri = Uri\Rfc3986\Uri::new('https://example.com/path?foo=bar');
echo $uri->getHost(); // example.com
echo $uri->getQuery(); // foo=bar
3. clone() with Property Modification
Essential for immutable value objects and readonly classes — the “wither” pattern without boilerplate.
$original = new Product(name: 'Widget', price: 9.99);
$discounted = clone($original, ['price' => 7.99]);
4. array_first() and array_last()
Replaces the verbose reset() / end() pattern without resetting the array’s internal pointer:
$first = array_first($items); // replaces reset($items)
$last = array_last($items); // replaces end($items)
5. #[\NoDiscard] Attribute
Warns developers when a function’s return value is silently ignored — useful for APIs where discarding the return value is almost certainly a bug.
6. Fatal Error Backtraces
Fatal errors — including timeout errors, which were notoriously opaque to debug — now include a full stack trace. A small change that saves hours.
7. OPcache Always Available
OPcache is now statically compiled into the PHP binary. It’s still controlled by opcache.enable in php.ini, but it’s always present — no more checking whether the extension is loaded. For WordPress sites, enabling OPcache is one of the highest-return performance improvements available. The WordPress performance guide covers the full OPcache and Lighthouse score optimisation process.
Prerequisites
- Ubuntu 24.04 LTS (Noble Numbat) or 22.04 LTS (Jammy Jellyfish) with
sudoaccess via SSH - A full database and files backup — never upgrade PHP on production without one
- A captured list of currently installed PHP extensions (Step 1 does this)
- For production: wait for the first bug-fix point release (8.5.1+) before deploying on high-traffic sites — Zend’s own recommendation for new major releases
Step 1: Inventory Your Current PHP Setup
Before changing anything, capture your current PHP environment. You’ll use this list to reinstall the same extensions for PHP 8.5.
# Save all currently loaded modules
php -m | tee php-modules.txt
# Save all installed PHP packages
dpkg -l | grep php | tee php-packages.txt
# Note your current version
php -v
Keep php-modules.txt and php-packages.txt. They’re your safety net if anything breaks after the upgrade.
Step 2: Update Your System
Start with a fresh package index:
sudo apt update && sudo apt upgrade -y
Install the helpers needed to add a PPA:
sudo apt install software-properties-common ca-certificates lsb-release apt-transport-https -y
Step 3: Add the Ondrej PHP PPA
Ubuntu’s default repositories don’t include PHP 8.5. The community-standard source is the Ondrej Surý PHP PPA — maintained by the same person who maintains the official Debian PHP packages, and used by thousands of production servers worldwide.
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
After this runs, you’ll see entries from ppa.launchpadcontent.net/ondrej/php/ubuntu in your package sources.
If you’re using Apache, also add the matching Apache PPA for the latest compatible Apache builds:
sudo add-apt-repository ppa:ondrej/apache2 -y
For Nginx:
sudo add-apt-repository ppa:ondrej/nginx -y
Step 4: Install PHP 8.5
You have two paths depending on your web server.
Option A — PHP 8.5 with Apache
Install the Apache module and the CLI:
sudo apt install php8.5 libapache2-mod-php8.5 -y
Disable the old PHP module, enable 8.5, restart Apache:
sudo a2dismod php8.3 # replace with your current version
sudo a2enmod php8.5
sudo systemctl restart apache2
Option B — PHP 8.5 with Nginx (PHP-FPM)
Nginx doesn’t run PHP directly — it passes requests to PHP-FPM over a Unix socket.
Install FPM and the CLI:
sudo apt install php8.5-fpm php8.5-cli -y
sudo systemctl enable --now php8.5-fpm
Update your Nginx server block to point to the PHP 8.5 socket:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
}
Test your config and reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Step 5: Install PHP 8.5 Extensions
Most real-world applications — WordPress, Laravel, Symfony, Drupal — need a standard extension set. Install it in one command:
sudo apt install -y \
php8.5-common \
php8.5-mysql \
php8.5-xml \
php8.5-curl \
php8.5-mbstring \
php8.5-zip \
php8.5-gd \
php8.5-intl \
php8.5-bcmath \
php8.5-imagick \
php8.5-soap \
php8.5-readline \
php8.5-opcache
| Extension | Why You Need It |
|---|---|
mysql |
Database connectivity (WordPress, Laravel, Drupal) |
mbstring |
Multibyte string handling (essential for UTF-8 text) |
xml |
RSS feeds, SOAP, sitemaps |
curl |
API calls, remote HTTP requests |
gd / imagick |
Image processing — uploads, thumbnails, WebP conversion |
zip |
Plugin installs, theme uploads, backup creation |
intl |
Internationalization, locale formatting |
bcmath |
High-precision math (ecommerce, finance, crypto) |
opcache |
Bytecode caching — largest single PHP performance gain |
Step 6: Verify the Installation
Check the CLI version:
php -v
Expected output:
PHP 8.5.x (cli) (built: ...)
Copyright (c) The PHP Group
Zend Engine v4.5.0, Copyright (c) Zend Technologies
with Zend OPcache v8.5.x, Copyright (c), by Zend Technologies
To verify the web server is also serving PHP 8.5, create a temporary info file:
sudo bash -c 'echo "<?php phpinfo();" > /var/www/html/phpinfo.php'
Visit http://your-server-ip/phpinfo.php and confirm the PHP Version at the top. Delete this file immediately after checking — it exposes sensitive server configuration:
sudo rm /var/www/html/phpinfo.php
Step 7: Switch Between PHP Versions
If you have multiple PHP versions installed and need to switch the CLI default:
sudo update-alternatives --set php /usr/bin/php8.5
Or use the interactive selector to choose from all installed versions:
sudo update-alternatives --config php
For Apache, use a2dismod / a2enmod as in Step 4. For PHP-FPM with Nginx, stop the old FPM service and start the new one:
sudo systemctl stop php8.3-fpm
sudo systemctl start php8.5-fpm
Then update the fastcgi_pass socket path in your Nginx config and reload.
Step 8: WordPress-Specific Post-Upgrade Checks
WordPress runs on PHP, so a version change affects every plugin, theme, and core hook. After upgrading:
- Clear all caches — object cache, page cache, OPcache. If you use WP Rocket, W3 Total Cache, or LiteSpeed, see the caching plugin comparison for the right flush procedure for each tool.
- Check Site Health (
Tools → Site Health) — it reports PHP version, extension availability, and configuration recommendations from WordPress core itself. - Disable plugins, then re-enable one by one if the site breaks after upgrading. Plugin incompatibilities are the most common cause of post-PHP-upgrade white screens.
- Check error logs —
/var/log/apache2/error.logor/var/log/nginx/error.logplus WordPress’s ownwp-content/debug.log(enable withdefine('WP_DEBUG_LOG', true)inwp-config.php). - Test WooCommerce checkout if your site sells — payment gateway libraries can behave differently across PHP versions.
- Run a full smoke test — the post-launch checklist covers the critical paths to verify after any major server change.
Common PHP 8.5 Upgrade Errors and Fixes
php8.5 package not found
The Ondrej PPA wasn’t added, or apt update wasn’t run after adding it. Rerun Steps 3 and 4.
Apache 403 Forbidden after enabling mod_php8.5
Usually two PHP modules active at the same time. Verify with apachectl -M | grep php — you should see only php8.5_module. Disable all others with a2dismod.
WordPress blank white screen after upgrade
Enable WP_DEBUG and WP_DEBUG_LOG in wp-config.php. Check debug.log for the specific fatal error — it almost always points to a specific plugin or theme file.
Call to undefined function errors
A required extension isn’t installed for PHP 8.5. Check php-modules.txt from Step 1 and install the corresponding php8.5-* package.
502 Bad Gateway (Nginx + PHP-FPM)
The fastcgi_pass socket path still points to the old PHP version. Verify the path in your Nginx server block matches what’s in /run/php/ — it should be php8.5-fpm.sock.
PHP-FPM not starting
Check sudo systemctl status php8.5-fpm and sudo journalctl -xe. Often caused by a php.ini syntax error — find the active config files with php8.5 --ini.
OPcache Configuration for PHP 8.5
OPcache is bundled in PHP 8.5 by default. Enable and tune it in /etc/php/8.5/fpm/php.ini (or /etc/php/8.5/apache2/php.ini for Apache):
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.jit=tracing
opcache.jit_buffer_size=100M
For WordPress specifically, opcache.validate_timestamps=0 gives the biggest throughput gain — it skips the file-modification check on every request. Set revalidate_freq=2 instead if you deploy code frequently and need the cache to clear faster. The WordPress performance guide covers the full OPcache tuning process alongside Lighthouse score optimisation.
Post-Upgrade: Ongoing Server Maintenance
A PHP upgrade is a good moment to review your broader server maintenance schedule. PHP point releases (8.5.1, 8.5.2, etc.) ship monthly and should be applied regularly — sudo apt update && sudo apt upgrade php8.5* is usually all it takes. The WordPress maintenance guide covers the full schedule: core, plugins, themes, PHP, and database optimisation.
If you’d rather not manage PHP upgrades on a schedule, managed WordPress maintenance plans handle server-level updates as part of the service. And if the upgrade broke something you’d rather not debug yourself, the bug fixes and rescue service is built for exactly this scenario.


