Ports: what is listening, and who can reach it
A port is a numbered door into the machine. The address beside it decides who can knock: 0.0.0.0 is the whole internet, 127.0.0.1 is the box itself.
A port is a numbered door into your machine, and something has to stand behind it or nothing answers. The part nobody explains is the address next to the port: one value means "anyone on the internet", the other means "only me". Same app, same port, different exposure.
What you just learned
ss -tulpn is the guest list: every row is one program holding one door open. Ignore Netid and State, they are plumbing. The Local Address column is the only one that decides who gets to knock. 0.0.0.0 means every network this box is on, including the public internet. 127.0.0.1 means the box talking to itself and nobody else, no firewall required.
This is the single most common way a self-hosted database ends up on the public internet. Nobody decided to expose it. A config file said 0.0.0.0, the port was open, and that was enough. Your app reaching a database on 127.0.0.1 works exactly the same and nobody outside can touch it.
And only one program can hold a given port at a time. That is all "address already in use" means: something already answered that door. Usually it is the copy of your app you forgot was still running, which is exactly what block 02 taught you to find.
Seen on a real server
nginx: [emerg] bind() to 0.0.0.0:3000 failed (98: Address already in use)- Two programs want port 3000. nginx retries five times, then 'still could not bind()'. Same cause as node's EADDRINUSE.
curl: (7) Failed to connect to 203.0.113.10 port 3001 after 0 ms: Connection refused- The app is bound to 127.0.0.1, so from the internet that door does not exist. For a database, that is exactly what you want.
You have been installing and running software this whole time. Next: where all of it actually came from.