Get the shape of the complaint first
Rule out the server before blaming the network
BASH
# Run from a machine on a different ISP, then from the server itself.
# Compare the phases: network delay shows up in connect/tls, server delay in ttfb.
curl -o /dev/null -s -w 'dns: %{time_namelookup}
connect: %{time_connect}
tls: %{time_appconnect}
ttfb: %{time_starttransfer}
total: %{time_total}
' https://example.com/tls and ttfb is small everywhere, the application answers quickly once the request arrives. If a technical customer runs the same command from the affected connection and sees a large connect time, the delay happens before your server is even involved. That only gets worse with packet loss, because lost handshake packets have to be retransmitted.
Next, ask the affected visitor for their public IP and search your access log for it with something like grep '203.0.113.45' against the right log file. The path depends on the stack. Nginx often logs to /var/log/nginx/access.log, and cPanel keeps per-domain logs in its domlogs directory. If the requests are there with normal status codes, the server answered and the delay is on the way back. If there is no entry at all, the request never arrived or was dropped earlier.
Two red herrings deserve a quick check here.
The first is a firewall ban. Mobile carriers and some fixed ISPs use carrier-grade NAT (CGNAT), which means many subscribers share one public IP. If Fail2ban, CSF, or a WAF blocked that IP because of one abusive user, a large group of that ISP's customers gets locked out at once. The signature is consistent hard timeouts or refusals for everyone behind that IP, at any hour, rather than slowness that rises and falls. Search your firewall's deny lists for the visitor's IP.
The second is DNS. If one ISP's resolvers still hold an old record after a migration, those users hit the old server. Ask the customer to run nslookup for the domain on the affected connection and confirm that it returns your current IP.
Trace the path with MTR in both directions
BASH
# From the server back to the affected visitor (report mode, 100 probes, show IPs and AS numbers)
mtr -rwbz -c 100 203.0.113.45
# From the customer side toward the site, using TCP 443 in case ICMP is filtered
mtr -rwbz -c 100 --tcp --port 443 example.comTEXT
Illustrative output format (addresses, names and values are placeholders)
HOST: web01 Loss% Snt Last Avg Best Wrst StDev
1.|-- gw.dc.example.net (198.51.100.1) 0.0% 100 0.5 0.6 0.3 1.1 0.1
2.|-- core1.dc.example.net (198.51.100.9) 0.0% 100 1.0 1.2 0.8 2.4 0.2
3.|-- ix-peer.example.net (192.0.2.10) 0.0% 100 2.1 2.3 1.9 4.0 0.3
4.|-- isp-border.example.net (192.0.2.77) 14.0% 100 118.4 121.7 64.2 210.5 30.1
5.|-- isp-core.example.net (203.0.113.1) 40.0% 100 119.9 123.0 66.0 215.3 31.4
6.|-- 203.0.113.45 13.0% 100 120.2 122.5 65.7 212.8 30.9-z flag adds AS numbers, which tell you which network owns each hop, so you can see exactly where your data center's network ends and the ISP's begins. Hostnames sometimes mention the exchange too, but that depends on how each operator names its interfaces.
Confirm it is the ISP's port, not a one-off
| Pattern you see | Where the problem most likely sits |
|---|---|
| Slow from every ISP, high ttfb on the server itself | Server or application |
| Hard timeouts for one ISP at all hours, clean MTR | Firewall ban on a shared CGNAT IP, or stale DNS |
| One ISP slow, worse at peak, loss starts at the ISP or exchange boundary and persists | Congested interconnect port |
| Path changes between runs, sudden intermittent drops | Route flapping or failing hardware on the link |
