Patch releases are routine; branch upgrades need a plan. Pick a target with long support, audit dependencies and code with Composer, PHPCompatibility and Rector, test on staging with a backup and rollback path, then upgrade production in stages.
Patch upgrades versus branch upgrades
Two kinds of PHP upgrade carry very different risk.
| Upgrade type | Example | Typical risk | How often |
|---|---|---|---|
| Patch release, same branch | 8.3.35 → 8.3.36 | Low; fixes only | Whenever a release ships |
| Minor version, new branch | 8.2 → 8.4 | Moderate; deprecations, removals, behaviour changes | Every one to four years |
| Major version | 7.4 → 8.x | Higher; significant language changes | Rarely |
Patch releases should be applied promptly as routine maintenance. This guide is about the second and third rows: moving to a new branch without breaking your application.
Step 1: Choose a target branch
Pick the newest branch that your framework, CMS and critical dependencies support. That gives you the longest support window and the fewest upgrades over time.
As of October 2026:
| Branch | Security support until | Notes |
|---|---|---|
| 8.5 | 2029-12-31 | Newest stable branch, active support until 2027-12-31 |
| 8.4 | 2028-12-31 | Active support until 2026-12-31 |
| 8.3 | 2027-12-31 | Security fixes only |
| 8.2 | 2026-12-31 | Security fixes only; ends in weeks |
| 8.6 | Not yet released | Release candidate; do not use in production |
Upgrading to 8.2 or 8.3 in late 2026 means planning another upgrade soon after. If you are on 8.1 or older, you are already on an unsupported branch, and those branches did not receive fixes for CVE-2026-109618 and CVE-2026-109619, the critical issues patched on 2026-10-21. See the PHP security support lifecycle for the full schedule.
Skipping branches, for example 8.1 directly to 8.4, is normal. You do need to read the migration notes for every branch you skip, because deprecations and removals accumulate.
Step 2: Read the migration guides
The PHP manual publishes a migration appendix for each minor version, listing backward-incompatible changes, deprecated features and new functions. For each branch between your current and target version, read:
- Backward incompatible changes: things that will break.
- Deprecated features: things that still work but emit deprecation notices and are likely to be removed later.
- Changed functions and removed extensions.
Make a short list of items that plausibly touch your code base. The PHP 8 ChangeLog is useful for checking individual fixes.
Step 3: Check dependencies with Composer
Most compatibility problems come from dependencies, not your own code. If you use Composer, check whether your locked packages accept the target PHP version.
First, confirm the current state:
composer check-platform-reqs
This compares the PHP version and extensions required by your installed packages with what the current environment provides. Run it inside the target environment (a container or staging server with the new PHP version) to see what fails there.
To test whether your dependency tree can resolve for the target version without changing the server, temporarily set the platform version and do a dry run:
composer config platform.php 8.4.27
composer update --dry-run
Composer reports packages that cannot be installed for that PHP version. Revert the platform setting afterwards if you do not want to keep it, or keep it set deliberately to the production version so local installs match production.
Also check:
composer outdated --direct
Packages several major versions behind are the usual blockers. Upgrade them on your current PHP version first, in separate, smaller changes.
Step 4: Scan your own code
PHPCompatibility
PHPCompatibility is a set of rules for PHP_CodeSniffer that detects code which is incompatible with a given PHP version range, such as removed functions or changed syntax.
composer require --dev phpcompatibility/php-compatibility
vendor/bin/phpcs -p src/ --standard=PHPCompatibility --runtime-set testVersion 8.4-
testVersion 8.4- means “8.4 and above”. Check the project’s README for the PHP versions covered by the release you install, since detection for the newest PHP versions depends on the release you use. Static analysis cannot catch everything, particularly behaviour that depends on runtime values.
Rector
Rector can apply many upgrade-related changes automatically. A minimal configuration:
<?php
// rector.php
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
->withPhpSets(php84: true);
Always preview first:
vendor/bin/rector process --dry-run
Review the proposed diff, apply it in a dedicated branch, and run your tests. Automated refactoring is fast but not infallible.
Static analysis and deprecation logs
If you use PHPStan or Psalm, run them configured for the target version. On your current production version, enable deprecation logging so you see notices your code already triggers:
; php.ini on staging
error_reporting = E_ALL
log_errors = On
display_errors = Off
Step 5: Build a staging environment that matches production
Testing on a laptop with a different configuration proves little. Staging should match production in:
- PHP version, SAPI (FPM or Apache module) and loaded extensions (
php -m) php.inisettings, especiallymemory_limit,max_execution_timeand upload limits- Web server, database version and cron jobs
Copy production data where privacy rules allow, or use a realistic anonymised dataset. Then run:
- Your automated test suite on the target version.
- A manual walkthrough of critical paths: login, checkout, forms, file uploads, admin screens, scheduled tasks and email sending.
- Background workers and CLI scripts, which often run under a different binary from the web server.
Log every error and deprecation notice, and fix fatal errors before scheduling production.
Step 6: Prepare the rollout
- Back up files and databases, and confirm that you can restore them.
- Keep the old version installed. On most servers, multiple PHP versions can coexist. Switching back should be a configuration change, not a reinstall.
- Write the rollback steps down, including the exact panel setting or configuration line to change.
- Choose a low-traffic window and make sure someone who knows the application is available.
- Upgrade in stages if you have several servers or sites: one server or a low-risk site first, then the rest.
# Rollback is a one-line change if both FPM versions remain installed
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
# fastcgi_pass unix:/run/php/php8.2-fpm.sock;
On shared hosting, the equivalent is the version dropdown in cPanel’s MultiPHP Manager or Select PHP Version, or the PHP settings page in Plesk. For a WordPress-specific walkthrough, see how to update PHP in WordPress.
Step 7: Upgrade and verify
After switching:
- Confirm the version served by the web server, not just the CLI. Use the hosting panel, WordPress Site Health or a short-lived
phpinfo()page that you delete straight afterwards. See how to check your PHP version. - Watch PHP and web server error logs closely for the first hours.
- Check scheduled tasks after their next run.
- Confirm the
X-Powered-Byheader is not exposing the new version; setexpose_php = Offif it is.
Step 8: Remove the old version
Once production has been stable for an agreed period, remove the old PHP packages or images. Leftover runtimes tend to be forgotten, miss future patches, and get picked up accidentally by cron jobs or scripts.
Make the next upgrade easier
- Fix deprecation notices continuously instead of saving them for upgrade time.
- Run CI against both your current and the next PHP version.
- Keep dependencies reasonably current, so a PHP upgrade does not also become a framework upgrade.
- Track branch end dates and start planning at least six months before security support ends.
The PHP version checker shows the lifecycle status and known vulnerabilities for any upstream version, which helps when deciding how soon each upgrade needs to happen.