Find which paths return 5xx in an Nginx access log
Count server errors per path with awk, merge query strings, and narrow by status code and time window — one-liners for the default combined format.
In the default combined format the status code is field 9, the request path is field 7, and the time is field 4. The output below comes from a test log generated for this page (one day, 2026-10-17, 578 lines, 58 of them 5xx), shortened to access.log. On a server the file is usually /var/log/nginx/access.log.
[1] Count 5xx responses per path.
$ awk '$9 ~ /^5/ {print $7}' access.log | sort | uniq -c | sort -rn | head 41 /api/upload 6 /api/search?q=log 3 /login 2 /api/search?q=nginx 2 /api/search?q=awk 2 /api/search?q=a+b 2 /api/items/7[2] Drop the query string so /a?x=1 and /a?x=2 count as one path. The /api/search lines above merge into one.
$ awk '$9 ~ /^5/ {split($7, p, "?"); print p[1]}' access.log | sort | uniq -c | sort -rn | head 41 /api/upload 12 /api/search 3 /login 2 /api/items/7[3] Break the errors down by status code. 502 and 504 mean the upstream app did not answer or was too slow; 500 is an error the app returned itself.
$ awk '$9 ~ /^5/ {print $9}' access.log | sort | uniq -c | sort -rn 22 500 20 502 11 504 5 503[4] Count per hour to find the spike. In field 4, [17/Oct/2026:10:05:12, characters 14–15 are the hour.
$ awk '$9 ~ /^5/ {print substr($4, 14, 2)}' access.log | sort | uniq -c 1 03 3 09 39 10 10 11 3 15 1 16 1 21[5] Keep only the busy hour (10:00) and count per path again.
$ awk '$4 ~ /17\/Oct\/2026:10:/ && $9 ~ /^5/ {split($7, p, "?"); print p[1]}' access.log | sort | uniq -c | sort -rn 28 /api/upload 9 /api/search 2 /loginAnalyze your Nginx log in the browser ↗ — nothing is uploaded.