# nginx 502: connect() failed (111: Connection refused) fix

Source: https://srvscripts.com/guides/nginx-502-connect-failed-111-connection-refused/
Updated: 2026-10-09
Publisher: srvScripts (https://srvscripts.com/)

**Short answer:** nginx 502 connect() failed (111: Connection refused) means nginx tried to connect to the backend named in the error line, but nothing was listening on that address, port or socket, so visitors got 502 Bad Gateway. Error 111 means Connection refused. Copy the address from the upstream field, then check for a listener with `sudo ss -ltnp`. If nothing is listening, start or repair the backend. If it listens somewhere else, make nginx and the backend use the same address, test with nginx -t, and reload.

## Read the error line

Visitors see **502 Bad Gateway**. The detail is in the nginx error log. A typical line looks like this:

```
2026/10/09 09:14:02 [error] 2817#2817: *431 connect() failed (111: Connection refused) while connecting to upstream, client: 203.0.113.24, server: example.com, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "example.com"
```

Read it from left to right. `connect() failed` means nginx tried to open a connection to a backend. The number and text in brackets are the system error. `while connecting to upstream` tells you it failed before any request was sent. The `upstream:` field is the address nginx tried. Here it is a FastCGI backend (usually PHP-FPM) on 127.0.0.1, port 9000.

If you are not sure where the error log is, ask nginx. The `-T` switch tests the configuration and prints it, so it is safe to run:

```
sudo nginx -T 2>/dev/null | grep -n error_log
sudo grep -h 'Connection refused' /var/log/nginx/error.log | tail -n 5
```

Change the log path in the second command to match what the first one shows. On DirectAdmin, per-domain nginx logs live under `/var/log/nginx/domains` by default.

## Tell 111 apart from similar errors

Each code points to a different cause. Read the text, not just the number.

- **111: Connection refused.** The connect(2) manual describes this as finding “no one listening on the remote address”. The host answered, but no process was listening on that port. For a unix socket, unix(7) says the path existed but was not a listening socket.

- **110: Connection timed out.** No answer arrived in time. Look at firewalls, load, and `proxy_connect_timeout`, not at a stopped service.

- **113: No route to host.** A network or routing problem between nginx and a remote backend.

- **2: No such file or directory.** The unix socket path in nginx does not exist. The pool may be stopped or the path may be different.

- **13: Permission denied.** For a unix socket, nginx lacks write permission on the socket file or search permission on a parent directory. connect(2) also lists SELinux policy as a cause of this error.

## Find which upstream refused

Copy the address from the `upstream:` field. Then list every place nginx sends traffic:

```
sudo nginx -T 2>/dev/null | grep -nE 'upstream|proxy_pass|fastcgi_pass|server unix:'
```

Match the address to one of these common backends:

- **PHP-FPM over TCP**, for example `fastcgi_pass 127.0.0.1:9000;`.

- **PHP-FPM over a unix socket**, for example `fastcgi_pass unix:/run/php-fpm/www.sock;`. nginx writes socket paths after a `unix:` prefix.

- **Apache behind nginx on cPanel.** cPanel’s NGINX with Reverse Proxy passes dynamic requests to Apache. cPanel documents that Apache usually moves to port 81, set in the `$CPANEL_APACHE_PROXY_PORT` map.

- **Apache behind nginx on DirectAdmin** (`webserver=nginx_apache`). DirectAdmin’s page does not fix a port number, so read it from the `nginx -T` output.

- **A Node.js or other app** on a local port, for example `proxy_pass http://127.0.0.1:3000;`.

- **A Docker container** published on a host port.

## Check whether anything is listening

These checks are read-only. Start with sockets. `-l` shows listening sockets, `-t` TCP, `-x` unix sockets, `-n` numeric ports and `-p` the owning process.

```
sudo ss -ltnp | grep -E ':9000|:81|:3000'
sudo ss -lxp | grep -i php
ls -l /run/php-fpm/www.sock
```

Use the port or path from your own error line. No output from `ss` means nothing is listening, which matches error 111. Next, check the service and its recent logs. Unit names vary. DirectAdmin uses names such as `php-fpm83`.

```
systemctl list-units --type=service | grep -iE 'fpm|httpd|apache|node'
sudo systemctl status php-fpm83
sudo journalctl -u php-fpm83 --since '1 hour ago'
```

For an HTTP backend, ask it directly. This skips nginx entirely:

```
curl -v -H 'Host: example.com' http://127.0.0.1:81/
```

If curl also reports connection refused, the problem is the backend, not nginx. curl cannot speak FastCGI, so for PHP-FPM rely on `ss` and the service status.

## Start or restart the backend

If the service is stopped or failed, start it and read the status again:

```
sudo systemctl restart php-fpm83
sudo systemctl status php-fpm83
```

If it fails to start, the status output and `journalctl -u` usually name the bad line or the missing file. Fix that first. Restarting in a loop will not help.

On cPanel, do not use the `nginx` command to stop or restart nginx. cPanel documents `/usr/local/cpanel/scripts/restartsrv_nginx` or WHM’s Service Manager instead.

## Make the listen address match nginx

Often both sides are running, but on different addresses. Compare the backend’s listen setting with the nginx line.

**PHP-FPM pool.** The `listen` directive accepts `ip.add.re.ss:port`, a bare port, or a socket path. If the pool says one thing and nginx says another, change one so they agree:

```
; PHP-FPM pool
listen = /run/php-fpm/www.sock

# nginx
fastcgi_pass unix:/run/php-fpm/www.sock;
```

php.net recommends a unix socket when nginx and PHP-FPM share a host. Socket access is controlled by `listen.owner`, `listen.group` and `listen.mode`. Wrong values there give error 13, not 111.

**localhost and IPv6.** nginx documents that a name resolving to several addresses is used as several servers, in round-robin. If `localhost` resolves to both `::1` and `127.0.0.1`, attempts to `::1` are refused when the backend listens on IPv4 only. With the default `max_fails=1` and `fail_timeout=10s`, nginx retries the next address, so pages may load while the log still fills with 111 errors. Check, then name the address explicitly:

```
getent ahosts localhost

# nginx: use the exact address the backend listens on
proxy_pass http://127.0.0.1:3000;
```

**Port changed after an update.** If a panel or package update moved the backend, the old port in nginx now refuses. On cPanel, compare the map in `/etc/nginx/conf.d/ea-nginx.conf` with Apache’s listening port. cPanel builds its nginx files with its ea-nginx script, so fix the Apache side first. On DirectAdmin, its documentation uses `da build rewrite_confs` to regenerate web server configs.

## Check for a crash or out-of-memory kill

A backend that keeps disappearing may be crashing or being killed. Read the kernel messages for this boot and the unit’s own journal:

```
sudo journalctl -k -b | grep -iE 'oom|killed process'
sudo journalctl -u php-fpm83 -b -n 100
```

If the kernel killed the process, restarting only buys time. Reduce the backend’s memory use, such as the number of PHP-FPM children, or add memory.

## Handle SELinux and Docker cases

**SELinux.** An SELinux denial shows up as error 13, not 111. On RHEL-family systems such as AlmaLinux, Red Hat’s NGINX guide sets `httpd_can_network_connect` so nginx can forward traffic. Check first, then enable it only if you need it:

```
getenforce
getsebool httpd_can_network_connect
sudo setsebool -P httpd_can_network_connect 1
```

**Docker.** Docker blocks access to container ports that are not published. If nginx on the host proxies to `127.0.0.1:8080`, the container must publish that port. Binding to loopback keeps it private:

```
docker ps
docker run -d -p 127.0.0.1:8080:80 your-image
```

The PORTS column of `docker ps` shows the mapping, such as `127.0.0.1:8080->80/tcp`. If nginx itself runs in a container, put both containers on the same user-defined network. Docker documents that containers on the same bridge network can reach each other’s ports.

## Confirm the fix

```
sudo ss -ltnp | grep ':9000'
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/
sudo tail -f /var/log/nginx/error.log
```

The listener should now appear. The site should return 200, or the redirect code you expect, instead of 502. Load a few pages and watch the log. No new `111: Connection refused` lines should appear.

## Undo a config change

Before editing any file, keep a dated copy:

```
sudo cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak-$(date +%F)
```

After editing, test before you reload. `nginx -t` checks syntax and tries to open the files the configuration refers to:

```
sudo nginx -t && sudo systemctl reload nginx
```

If a reload still fails, nginx documents that the master process rolls back and keeps the old configuration. To undo fully, copy the backup over the edited file, run `nginx -t` again, and reload. Use the same pattern for a PHP-FPM pool file, then restart the pool. To undo the SELinux change, run `sudo setsebool -P httpd_can_network_connect 0`.

**Official documentation (checked 9 October 2026):** [Module ngx_http_upstream_module](https://nginx.org/en/docs/http/ngx_http_upstream_module.html) · [Module ngx_http_proxy_module](https://nginx.org/en/docs/http/ngx_http_proxy_module.html) · [Module ngx_http_fastcgi_module](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) · [nginx: Command-line parameters](https://nginx.org/en/docs/switches.html) · [PHP Manual: FPM Configuration](https://www.php.net/manual/en/install.fpm.configuration.php) · [connect(2) – Linux manual page](https://man7.org/linux/man-pages/man2/connect.2.html) · [unix(7) – Linux manual page](https://man7.org/linux/man-pages/man7/unix.7.html) · [cPanel: The Default Configuration of NGINX with Reverse Proxy](https://docs.cpanel.net/knowledge-base/nginx/the-default-configuration-of-nginx-with-reverse-proxy/) · [DirectAdmin: Nginx+Apache](https://docs.directadmin.com/webservices/nginx_apache/) · [Red Hat RHEL 9: Setting up and configuring NGINX](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/deploying_web_servers_and_reverse_proxies/setting-up-and-configuring-nginx_deploying-web-servers-and-reverse-proxies) · [Docker: Port publishing and mapping](https://docs.docker.com/engine/network/port-publishing/) · [systemd: journalctl](https://www.freedesktop.org/software/systemd/man/latest/journalctl.html) · [DirectAdmin: All directadmin.conf values](https://docs.directadmin.com/directadmin/general-usage/all-directadmin-conf-values.html)

## Nginx 502 connect() failed (111: Connection refused) at a glance

In short: Why nginx logs connect() failed (111: Connection refused) and shows 502 Bad Gateway, and how to find the backend that refused, fix it and confirm the fix.

Nginx 502 connect() failed (111: Connection refused): what this guide covers.

**Related:** [nginx Config Checker: Find Security and Syntax Mistakes](https://srvscripts.com/tools/nginx-config-checker/) · [PHP-FPM Calculator: pm.max_children and Spare Servers](https://srvscripts.com/tools/php-fpm-calculator/) · [HTTP Status Codes Reference](https://srvscripts.com/tools/http-status-codes/) · [CustomBuild Web Stack 2026: Apache, nginx or LiteSpeed, Best Pick](https://srvscripts.com/guides/custombuild-web-stack-apache-nginx-litespeed/).
