Rules added with iptables directly are gone after a restart, which is how a database port ends up open on a machine that was firewalled last Tuesday.
ufw default deny incoming
ufw default allow outgoing
ufw allow from 10.0.0.0/8 to any port 3306
ufw allow 22/tcp
ufw allow 80,443/tcp
ufw --force enable
ufw status numbered
UFW persists its rules and reapplies them at boot, which is the entire reason to use it over raw iptables for a handful of rules. Allowing SSH before enabling is the step whose omission ends a remote session permanently. Docker is the notable exception to all of this — it writes its own iptables rules that bypass UFW entirely, so a published container port is reachable regardless of what the firewall says, and that surprise deserves to be checked rather than assumed.