An exposed database does not break your website. It works perfectly while it is exposed, there is no error to notice and no customer complaint to escalate — which is exactly why these last for years rather than days.
Almost none of them are opened deliberately. They are opened temporarily during a migration, a debugging session or an initial setup, and then the temporary state becomes the permanent one because nothing ever draws attention to it.
Databases: the ones that matter most
Database ports should be reachable only from your application servers, over a private network — never from the public internet. The usual suspects are the defaults: PostgreSQL on 5432, MySQL and MariaDB on 3306, MongoDB on 27017, Redis on 6379, Elasticsearch on 9200, Microsoft SQL Server on 1433, and Memcached on 11211, which additionally makes an excellent traffic amplifier for attacks on other people.
Two of those deserve special mention because their historical defaults were dangerous. Redis and Elasticsearch were both designed for trusted internal networks and shipped for years with no authentication enabled. Both have since fixed this — Redis has had protected mode on by default since 3.2, Elasticsearch enables authentication out of the box from version 8 — but the internet is full of older installations, upgraded configurations that carried the old settings forward, and containers started with the protections explicitly disabled. An exposed instance of either has frequently meant a full data read, and in Redis's case sometimes remote code execution, with no credentials needed at all.
The consequence of exposure here is not "an attacker might eventually find a vulnerability". It is often direct access to your customer data, today, using nothing but a client.
Remote administration
These give an attacker a login prompt, which means they can attack it continuously and invisibly:
- SSH (22) — usually the one port that legitimately must be reachable. The realistic goal is to reduce it: key-based authentication only, password authentication disabled, and access restricted to known addresses or a VPN where practical.
- RDP (3389) — Windows remote desktop, and one of the most consistently abused entry points on the internet. It should be behind a VPN. Not hardened and exposed. Behind a VPN.
- Database admin panels — phpMyAdmin, Adminer and similar tools running over HTTP. These are web applications with their own vulnerability history, sitting directly in front of your data.
- SMB (445) — Windows file sharing, and the route several of the largest ransomware outbreaks took. There is no configuration that makes this safe to expose; it belongs on a private network or behind a VPN.
- VNC (5900) — remote desktop with a weak authentication model and a long history of being left open with no password at all.
- Container and orchestration APIs — an exposed Docker daemon on 2375 is equivalent to handing out root on the host, without authentication. Port 2376 is the TLS-protected equivalent and is only as safe as its client-certificate configuration. An exposed Kubernetes API on 6443, or a kubelet on 10250, has historically allowed command execution inside running containers.
Legacy plaintext protocols
FTP on 21 and Telnet on 23 transmit credentials in the clear. Anyone positioned between the client and the server reads the password. If either is open, the question is not how to harden it but what is still using it and how quickly it can be replaced with SFTP or SSH.
Files, not just ports
The same category of accident produces publicly readable files, and these are often faster to exploit than an open port because they need no protocol knowledge at all:
.envfiles, which typically contain database passwords, API keys and payment credentials in plain text.- Database dumps —
backup.sqland friends, left in the web root after a migration. - An exposed
.gitdirectory, which allows reconstruction of your entire source history, including any credentials committed at any point. - Editor and backup leftovers —
config.php.bak,config.php~, and similar. These are usually served as plain text rather than executed, which means the source and its credentials are readable in a browser.
How to check
Check from outside your own network. This is the part people get wrong: a check run from inside the office or from the server itself tests a path that is not the one attackers use, and firewall rules frequently differ between them. Use a machine on an unrelated connection, or a scanning service, and scan the public address your domain actually resolves to.
Note also that this is not a one-off task. Firewall rules get rebuilt during migrations, cloud security groups are edited by people who are not thinking about your database, and a temporary rule added during an incident is exactly the kind of thing that is never removed. A check tells you about today; only a repeated check tells you about next quarter.
What to do when you find something
Close it first, investigate second. Restrict the port to the addresses that need it — a private network, a security group, a firewall rule — and only then work out how long it was open.
Then assume exposure. If a database was reachable, treat its contents as potentially read and its credentials as compromised. Rotate them. Access logs may tell you something, but absence of evidence in a log that may not have been enabled is not evidence of absence.
Which ports should never be exposed to the internet?
Database ports above all — PostgreSQL 5432, MySQL 3306, MongoDB 27017, Redis 6379, Elasticsearch 9200, SQL Server 1433 — which should be reachable only from your application servers over a private network. Also remote administration: SMB on 445 and RDP on 3389 belong behind a VPN, database admin panels such as phpMyAdmin should not be public, and an exposed Docker daemon on 2375 is equivalent to giving away root. Legacy plaintext protocols such as FTP and Telnet transmit credentials in the clear and should be replaced.
How would I know if my database is exposed?
You would not notice from normal operation, which is the core problem: an exposed database does not break anything, produces no error and generates no customer complaint, so it stays open for years. The only way to know is to check from outside your own network — a scan run from inside the office or from the server itself tests a different path, and firewall rules frequently differ between them.
Why is an exposed Redis or Elasticsearch instance especially serious?
Because Redis and Elasticsearch were both designed for trusted internal networks and shipped for years with no authentication enabled. Both have since changed their defaults — Redis at 3.2, Elasticsearch at version 8 — but older installations, upgraded configurations and containers started with the protections disabled remain common. An exposed instance has frequently meant a complete data read with no credentials required at all, and in Redis's case sometimes remote code execution. The risk is not that an attacker might eventually find a vulnerability — it is direct access to your data using nothing but a standard client.
What should I do if I find an exposed port?
Close the port first and investigate afterwards: restrict the port to the addresses that need it via a firewall rule, security group or private network, and only then work out how long it was open. Then assume exposure — if a database was reachable, treat its contents as potentially read and its credentials as compromised, and rotate them. Absence of evidence in a log that may not have been enabled is not evidence of absence.
Where VulnControl fits
VulnControl scans a curated set of high-signal TCP ports from outside your network and reports databases, remote administration and admin panels reachable from the public internet, alongside a check for sensitive files left publicly downloadable. It makes ordinary connections and reads what services volunteer — it never attempts to exploit anything or log in — and it only scans hosts you have verified you own. Because it runs on a schedule, it also catches the rule that gets re-added during next year's migration.