
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Debugging PHP applications often fails not because of code complexity, but because of misconfigured tooling. Getting PHP Xdebug 3 configuration for modern IDEs right is the difference between guessing at variable states and inspecting them precisely in real time. Whether you are running a local LAMP stack or a containerized Laravel environment, the protocol has changed significantly since version 2, requiring updated INI directives and IDE listener settings. This guide provides the exact configurations needed to establish a stable debug session in 2026.
xdebug.mode=debug, xdebug.start_with_request=yes, and xdebug.client_port=9003 in your php.ini. For Docker or remote servers, you must also configure xdebug.client_host=host.docker.internal and map server paths to local project directories in your IDE to resolve breakpoints correctly.How does PHP Xdebug 3 configuration for modern IDEs differ from version 2?
Xdebug 3 was a complete rewrite focused on performance and configurability, breaking backward compatibility with version 2. If you are migrating legacy configs or following outdated tutorials from before 2024, your debugger will silently fail. The most critical change is the replacement of the monolithic xdebug.remote_enable with granular modes. In production-like environments, this distinction matters immensely; enabling profiling or tracing accidentally can degrade performance by orders of magnitude.
The default port has also shifted from 9000 to 9003 to avoid conflicts with PHP-FPM. While you can revert this, sticking to 9003 is now the standard convention across Ubuntu PHP installations and Docker images. Another frequent stumbling block is the removal of xdebug.remote_connect_back. This directive was a security risk and has been replaced by explicit host configuration. In my experience auditing development environments, teams that rely on auto-detection often face intermittent failures when working across VPNs or WSL2; explicit configuration eliminates this class of bugs entirely.
How do I configure Xdebug 3 INI settings for local development?
For a native local installation, your php.ini or a dedicated 20-xdebug.ini file needs only four directives to cover 90% of debugging scenarios. Avoid copying entire configuration blocks from older guides; minimalism prevents side effects.
; /etc/php/8.4/mods-available/xdebug.ini
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.client_host=127.0.0.1
xdebug.log=/tmp/xdebug.log
xdebug.idekey=VSCODE Understanding each directive prevents future headaches:
- xdebug.mode: Accepts a comma-separated list. Use
debugfor step debugging. Adddevelopif you want enhancedvar_dump()output and stack traces. Never enableprofileortraceunless actively analyzing performance, as they generate massive I/O overhead. - xdebug.start_with_request: Set to
yesto attempt a debug session on every request. In production, usetriggerand rely on browser extensions or query parameters (?XDEBUG_TRIGGER=1) to activate debugging on demand. For local dev,yessaves you from managing trigger cookies. - xdebug.client_host: The IP where your IDE listens. For local setups, this is always
127.0.0.1. Do not uselocalhost, as IPv6 resolution (::1) can cause connection timeouts on some systems. - xdebug.log: Essential for troubleshooting. If the IDE doesn't break, check this file first. It records connection attempts, protocol errors, and path mapping failures. Ensure the directory is writable by your web server user.
After updating the configuration, restart your PHP-FPM service or Apache/Nginx. Verify the extension loaded correctly by running php -m | grep xdebug or checking phpinfo(). If the module appears but debugging fails, the log file specified in xdebug.log is your primary diagnostic tool. Many developers skip this step and waste hours guessing at network issues when the log explicitly states "Could not connect to client."
How do I set up Xdebug 3 in Docker with VS Code or PhpStorm?
Containerized environments introduce network isolation that breaks naive Xdebug configurations. The PHP process inside the container cannot reach 127.0.0.1 on your host machine. You must bridge this gap using special DNS names and path mappings. This is where most Docker Laravel setups encounter friction.
Docker-specific Xdebug INI configuration
Your Dockerfile or docker-compose override should inject these settings. Never bake debug config into production images; use a separate xdebug.ini mounted only in development services.
# docker-compose.dev.yml
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- XDEBUG_MODE=debug
- XDEBUG_CONFIG="client_host=host.docker.internal start_with_request=yes" On Linux hosts, host.docker.internal requires the extra_hosts directive shown above. macOS and Windows Docker Desktop handle this automatically. If you are running WSL2, verify that your IDE firewall allows inbound connections on port 9003 from the WSL virtual adapter.
IDE path mapping essentials
The debugger matches breakpoints by comparing absolute file paths. Inside the container, your code lives at /var/www/html. On your host, it might be /home/khimananda/projects/laravel-app. Without mapping, the IDE receives a breakpoint hit for an unknown file and ignores it.
- VS Code: In
.vscode/launch.json, add"pathMappings": { "/var/www/html": "${workspaceFolder}" }inside your configuration object. - PhpStorm: Navigate to Settings → PHP → Servers. Add a server matching your container's hostname, then map the local project root to
/var/www/html. Enable "Use path mappings" for all requests.
A common mistake is mapping the wrong directory level. Map the exact root where your index.php resides, not a parent folder. Test this by setting a breakpoint in a known entry point and checking the Xdebug log for "resolved breakpoint" messages.
Why is my Xdebug breakpoint not triggering in 2026?
When configuration looks correct but debugging fails, the issue usually falls into one of three categories: network blocking, path mismatches, or mode conflicts. Systematic elimination beats random tweaking.
| Symptom | Likely Cause | Fix |
|---|---|---|
| No connection attempt in log | xdebug.mode missing or misspelled | Verify php -i | grep xdebug.mode returns debug |
| Connection refused in log | Firewall blocking port 9003 or wrong client_host | Check UFW/firewall rules; confirm IDE listener is active |
| Connected but no breakpoint hit | Path mapping mismatch | Compare server path in log vs IDE mapping; adjust case sensitivity |
| Breakpoint hits wrong line | OPcache serving stale bytecode | Disable OPcache in dev or set opcache.validate_timestamps=1 |
| Session starts then drops immediately | IDE key mismatch or timeout | Align xdebug.idekey with IDE config; increase xdebug.connect_timeout_ms |
Always consult the Xdebug log before changing configurations. A log entry like I: Connecting to configured address 'host.docker.internal:9003'... followed by E: Could not connect confirms a network issue. Conversely, I: Connected to client followed by silence indicates a path mapping problem. For teams working with Laravel Sail, remember that Sail abstracts some Docker networking; use sail debug instead of manually configuring Xdebug to leverage built-in presets.
Another subtle issue in 2026 involves PHP 8.4's JIT compiler. When JIT is enabled, Xdebug may fail to intercept certain optimized code paths. If you encounter inconsistent breakpoint behavior specifically with JIT-enabled builds, disable JIT temporarily during debug sessions by setting opcache.jit=disable. This trade-off is acceptable in development where correctness trumps raw execution speed.
Streamline Your PHP Debugging Workflow Today
Correct PHP Xdebug 3 configuration for modern IDEs transforms debugging from a frustrating chore into a precise engineering practice. Start with the minimal INI settings, validate connectivity through logs, and only then layer in IDE-specific path mappings. Resist the urge to copy-paste bloated configurations; understanding each directive ensures your setup survives framework upgrades and infrastructure changes. If your team struggles with persistent debugging issues across containerized environments or needs help establishing standardized development workflows, reach out to discuss your specific setup.