ufw does not control ports published by Docker
ufw status shows only 22 and 80 allowed. After docker run -p 3306:3306, the database answers from the internet.
Docker inserts DNAT rules in the nat table and the traffic is accepted in FORWARD, never reaching ufw's INPUT chain. ufw's default deny is simply not in the path.
Three options: bind to loopback, -p 127.0.0.1:3306:3306, which is simplest and easiest to forget; add rules to the DOCKER-USER chain, the hook Docker provides; or run Docker with iptables=false and manage NAT yourself, which is painful.
Check with iptables -t nat -L DOCKER -n.