Error fix · Server errors

nginx "connect() failed (111: Connection refused)" Upstream Fix

Fix nginx "connect() failed (111: Connection refused) while connecting to upstream" by checking that PHP-FPM or your app listens where nginx expects.

Error messageconnect() failed (111: Connection refused) while connecting to upstream

By SiteDownCheck Editorial · Updated October 5, 2026 · 4 min read

Error 111 is the operating system's ECONNREFUSED. nginx tried to open a connection to your backend, and the machine at that address answered immediately that nothing is listening on that port or socket. The visitor sees 502 Bad Gateway. Unlike a timeout, a refusal is instant, and it nearly always means the backend is stopped, crashed or bound somewhere else.

The line appears in /var/log/nginx/error.log:

[error] 2417#2417: *91 connect() failed (111: Connection refused) while connecting to upstream, client: 198.51.100.4, server: example.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "example.com"

The upstream: value in that line is the exact address nginx used, and it is where you start. For the general 502 workflow, see Fix 502 Bad Gateway.

Causes, most likely first

  1. The backend service is not running. PHP-FPM, Node, Gunicorn or a container crashed, was stopped, or has not started yet after a reboot.
  2. nginx points at the wrong port or socket. For example, fastcgi_pass says 127.0.0.1:9000 while PHP-FPM listens on a Unix socket, or a PHP upgrade changed the socket name.
  3. The backend listens on a different interface. It binds to 127.0.0.1 but nginx connects from another container or host, or the reverse.
  4. IPv4 versus IPv6 mismatch. localhost resolves to ::1 but the service listens on IPv4 only.
  5. Container networking. Inside Docker, 127.0.0.1 is the nginx container itself, not the app container.
  6. A crash loop where the service starts, dies and restarts, so connections are refused part of the time.

Step 1: take the upstream from the log and test it

Whatever the log's upstream: field says, test that exact address from the nginx host:

curl -v http://127.0.0.1:3000/
# For a Unix socket (fastcgi_pass unix:/run/php/php8.2-fpm.sock):
ls -l /run/php/

If curl prints Connection refused, the problem is confirmed outside nginx. Now see who is listening:

sudo ss -ltnp | grep -E ':3000|:9000'
sudo ss -lxp | grep php          # Unix sockets

No line for your port means nothing is listening.

Step 2: start the service and read why it stopped

sudo systemctl status php8.2-fpm
sudo systemctl restart php8.2-fpm
sudo journalctl -u php8.2-fpm -n 50 --no-pager

For Node apps managed by systemd or PM2, use pm2 logs or journalctl -u yourapp. Typical reasons for a stopped service are a config syntax error after an edit, a port conflict, a missing environment variable, or the OOM killer. Make sure it starts at boot: sudo systemctl enable php8.2-fpm.

Step 3: make nginx and the backend agree

Compare the two sides.

sudo nginx -T 2>/dev/null | grep -E "fastcgi_pass|proxy_pass|upstream"
grep -E "^listen" /etc/php/8.2/fpm/pool.d/www.conf

The values must match exactly. After a PHP version change, update the socket path:

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}

Test and reload with sudo nginx -t && sudo systemctl reload nginx.

Step 4: IPv6 and localhost

If curl to http://localhost:3000 fails but http://127.0.0.1:3000 works, the name is resolving to ::1. Use the explicit IPv4 address in proxy_pass, or make the app listen on both. A literal address in the config removes the ambiguity.

Step 5: containers

Inside a Docker Compose network, use the service name, not 127.0.0.1:

location / {
    proxy_pass http://app:3000;
}

The app must listen on 0.0.0.0 inside its container, not only 127.0.0.1, and both containers must share a network. nginx also resolves hostnames only at startup, so if the app container gets a new IP, reload nginx. Read Docker website down checklist for more.

How to verify

Run curl -I https://example.com/ and expect a 200 or the application's normal response instead of 502; the HTTP Status Checker does the same from outside your server. Watch the log for a few minutes with sudo tail -f /var/log/nginx/error.log. If the service is on another host, the Port Checker shows whether the port is reachable. Because a crashed backend can return at any time, an Uptime Monitor on the site is the cheapest alarm.

Next steps

FAQ

What does 111 mean?

It is Linux errno 111, ECONNREFUSED: the target host replied that no process accepts connections on that address and port.

How is this different from a timeout?

A refusal comes back immediately because the host actively rejected the connection. A timeout means no answer arrived at all, often caused by a firewall dropping packets.

Why did it start after I upgraded PHP?

The new PHP-FPM version usually uses a different socket file name and service name, such as php8.3-fpm.sock. Update fastcgi_pass to match.

The service is running, so why is it refused?

It is probably listening on a different address, port or socket than nginx uses. Compare ss -ltnp output with the upstream: value in the log line.

Get notified when this fix updates

Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.

This page is general information written by our editorial team and updated when documentation changes. Servers and providers differ, so test changes safely first. See our editorial policy and disclaimer.