25
The server-to-server mail relay port — the one your app should almost never dial, and the one that times out on a cloud VM because the provider blocks it, not because the mail server is down.
Run the line for your platform. Each one names the process holding the port and the address it bound to, which is usually the whole answer.
sudo lsof -nP -iTCP:25 -sTCP:LISTEN`-n` and `-P` keep hosts and ports numeric so the row reads `:25` rather than `:smtp`. The NAME column carries the bound address: `127.0.0.1:25` is a local-only mailer, typical of a default Postfix install that exists to deliver cron output, and `*:25` means the machine is accepting mail from the network. COMMAND is usually `master` for Postfix, which is easy to mistake for something unrelated. Empty output and an exit status of 1 mean nothing is listening. Without `sudo` you will not see a root-owned daemon at all.
sudo ss -tlnp 'sport = :25'`-t` for TCP, `-l` for listening sockets only, `-n` for numeric ports and `-p` for the owning process. `127.0.0.1:25` is the local-delivery-only default that most distributions ship; `0.0.0.0:25` or `[::]:25` means the server is reachable from the network and should be a deliberate decision. The process column reads like `users:(("master",pid=812,fd=13))`. Without `sudo` the socket still shows but the process is blank.
sudo netstat -tlnp | grep ':25 'The net-tools equivalent for hosts without `ss`. Same flag meanings; the final PID/Program name column needs superuser privileges for sockets you do not own, and its own man page cautions the value is not trustworthy. The trailing space in the pattern matters — without it `:25` also matches `:2525`, a very common alternative submission port, and `:25000`.
netstat -ano | findstr :25`-a` includes listening ports, `-n` keeps everything numeric and `-o` adds the owning PID in the final column; turn it into a name with `tasklist /FI "PID eq 1234"`. Because `findstr` matches substrings, `:25` also matches `:2525` and `:25565`, so read the whole Local Address before acting. On a workstation an unexpected listener here is worth investigating rather than killing.
`nmap -Pn -p 25 mx.example.com` tells you what the port does from where you are standing. `open` means the handshake completed, `closed` means the host sent a reset so it is reachable with nothing listening, and `filtered` means nothing came back. On port 25 specifically, `filtered` very often means your own network is blocking the outbound packet rather than the mail server refusing it — repeat the scan from a different network before blaming the far end. Add `--reason` to see which of the three states was actually observed, and `-sV` to read the SMTP banner, which names the server software and often the hostname it thinks it has. Scan only hosts you are responsible for.
| What you see | What it means |
|---|---|
The send hangs, then: Connection timed out / ETIMEDOUT connecting to mx.example.com:25 | Nothing answered the SYN. On a cloud VM or a home connection this is almost always an egress block on port 25 rather than a problem at the destination — Google Cloud blocks it by default and consumer ISPs commonly do too. Confirm by trying port 587 to the same host: if that connects and 25 does not, the block is on your side. Switch to authenticated submission on 587 or 465. |
Connection refused connecting to mail.example.com:25 | The host is reachable and its kernel actively rejected the connection, so no MTA is listening on the address you dialled. Check you resolved the domain's MX record rather than its A record — the web server and the mail server are usually different hosts — and run the probe on the mail server itself. |
550 5.7.1 Relaying denied / 554 5.7.1 <you@example.net>: Relay access denied | Not a port problem at all. The connection succeeded and the server read your envelope before refusing it: it accepts mail for its own domains but will not forward mail for yours. Either you are talking to the wrong server, or you meant to use an authenticated submission port. A server that answers this correctly is a server that is not an open relay. |
bind: Address already in use when starting Postfix, Exim or a test SMTP server | Another mail daemon already holds 25 — very often a distribution's default Postfix or Exim that was installed as a dependency and bound to loopback. Run the platform probe, note the bound address, and disable the incumbent rather than fighting it; a listener on `0.0.0.0:25` blocks any second bind on a specific address. |
bind: Permission denied on port 25 as a normal user | Ports below 1024 are privileged, so the kernel returns EACCES before anything about mail is considered. Start the daemon through its init system, or for a local test listener use a high port such as 2525 and point your client at that. |
Mail is delivered but arrives unencrypted, or a STARTTLS negotiation fails mid-session | STARTTLS on 25 is opportunistic by design: the session starts in plaintext and upgrades only if the server advertises the extension. A missing advertisement, a stripped one, or a certificate the sender will not accept results in either a plaintext delivery or a dropped session, depending on the sender's policy. If confidentiality is required, use implicit TLS on 465 where the connection is encrypted before any SMTP command is sent. |
IANA assigns port 25 to `smtp` for both TCP and UDP, referencing the RFC 5321 series; only TCP is used. RFC 5321 requires a receiving mail server to listen on "the port (specified by IANA as port 25) at all times". The important distinction that almost every failing integration gets wrong is who port 25 is for: it carries mail between mail transfer agents, one organisation's server handing a message to another's. It is not the port an application uses to send mail through a provider. That job belongs to the submission ports — 587, registered as `submission` by RFC 6409, and 465, registered as `submissions` for implicit TLS by RFC 8314. Submission ports authenticate you; port 25 generally does not, because the sending server is a stranger. Encryption on 25 is opportunistic: RFC 3207 defines a STARTTLS extension that upgrades an already-open plaintext session, so if the far end does not advertise it, or an on-path device strips the advertisement, the message goes out in clear and nothing fails loudly. Locally, the process holding 25 is usually `master` for Postfix, `exim4`, or `sendmail`, and many Linux images start one of these bound to loopback purely so `cron` can mail its output — that listener is harmless and is a common source of a surprising `netstat` line.
Two separate questions live here. Inbound: do not run a listener on 25 unless you are genuinely a mail server for a domain. A misconfigured server that relays for anyone is found by scanners within hours, is used to send spam at volume, and lands the address on blocklists that are far easier to get onto than off. If you do run one, verify it relays only for your own domains and authenticated users, rate-limit it, and publish SPF, DKIM and DMARC so forged mail from your domain is rejected elsewhere. Outbound: assume port 25 is blocked and design around it. Google Cloud states plainly that it "blocks egress packets sent to TCP destination port 25 of an external IP address", noting the block does not apply to internal destinations or to ports 465 and 587, and residential ISPs have blocked outbound 25 for years for the same anti-spam reason. This is why a mailer that works on a laptop hangs forever on a VM. Send through a provider on 587 or 465 with credentials and TLS instead of dialling recipient servers directly — you also inherit their reputation, which is the part that actually determines whether your mail is delivered.
All of these run in your browser — nothing is uploaded.
Ports people usually end up checking in the same session as 25.
Almost always permissions. lsof and ss list the socket but hide the owning process when it belongs to another user, so a server started by a system account, by a container runtime or by launchd shows up as an anonymous listener until you re-run the command with sudo. On Windows the opposite happens: netstat shows nothing at all, yet a bind still fails, which means the port sits inside a range that Hyper-V, WSL2 or Docker Desktop reserved at boot.
Look at what it is first. An orphaned dev server is safe to kill; a database with a write in flight is not, and neither is a system service that something else depends on. If the owner is a container, stop the container instead — killing the process the host sees only makes the runtime restart it. When the process is something you need, moving your own service to another port is the faster fix.
The listener bound to 127.0.0.1 rather than 0.0.0.0. The probes on every page print the bound address next to the process for exactly this reason: a loopback bind is reachable from the machine itself and from nowhere else, no matter how the firewall is configured. Many frameworks made that the default deliberately, so it is usually a flag rather than a bug. If the address is already 0.0.0.0 and it still fails, the next suspect is a host firewall or a cloud security group.
Barely. Internet-wide scanners sweep the whole port range continuously, so an unusual number buys hours, not safety, and it costs you every colleague who now has to remember it. It does cut the noise in your logs from opportunistic scans of the default port, which is a real if modest benefit. Authentication, a firewall that restricts source addresses, and not exposing the service at all are the measures that actually change the outcome.
Still stuck on port 25? browse every port in the reference — or go back to the failure message you actually got, above.