Wie thuis een MySQL-server draait en die af en toe op afstand wil benaderen, loopt vroeg of laat tegen een muur van foutmeldingen aan. In dit artikel neem ik je mee door een concreet probleem dat ik onlangs oploste: MySQL Workbench kon geen verbinding maken via VPN, terwijl “gewoon” verbinden op het lokale netwerk prima werkte. De oplossing bleek uiteindelijk simpel, maar de weg ernaartoe leert veel over hoe MySQL, VPN’s en netwerken samenwerken.
Het startpunt: verbonden, maar toch geen toegang
De situatie: ik was via een UniFi Travel Router met een VPN-verbinding naar mijn thuisnetwerk verbonden. Screensharing naar mijn Mac mini werkte feilloos — dus de VPN-verbinding zelf functioneerde prima. Maar zodra ik in MySQL Workbench probeerde in te loggen, kreeg ik simpelweg geen verbinding.
Dat verschil is meteen een belangrijke aanwijzing: als het ene protocol (screensharing) wél werkt en het andere (MySQL) niet, ligt het probleem zelden bij de VPN-tunnel zelf. Het zit hem meestal in poort-specifieke restricties of in de configuratie van de dienst waarmee je probeert te verbinden.
Stap 1: onderscheid maken tussen “geen verbinding” en “geen toegang”
Bij dit soort problemen is de eerste vraag altijd: komt het verkeer er überhaupt door, of wordt de verbinding actief geweigerd? Dat zijn twee compleet verschillende problemen met andere oplossingen.
Een snelle test om dit te isoleren:
nc -zv 192.168.10.50 3306
Als dat een “succeeded” teruggeeft, weet je dat de poort bereikbaar is en dat het probleem verderop zit — bij gebruikersrechten in MySQL zelf. Krijg je een timeout, dan ligt het bij de firewall of het netwerk.
In mijn geval bleek al snel uit de foutmelding in Workbench dat de verbinding wél tot stand kwam:
Access denied for user 'thuis-mac'@'192.168.55.12' (using password: YES)
Dat is duidelijke taal: MySQL wéét dat er iemand aanklopt, maar wijst de gebruiker af. Geen netwerkprobleem dus, maar een rechten-probleem.
Stap 2: het IP-adres van de VPN-client achterhalen
De foutmelding onthulde iets cruciaals: het IP-adres waarmee ik verbond via VPN (192.168.55.12) was compleet anders dan het IP-adres waarvoor mijn MySQL-gebruiker oorspronkelijk was ingesteld (een adres uit het normale thuisnetwerk-bereik, 192.168.10.x).
Dat verklaart meteen waarom lokaal verbinden wél werkte en via VPN niet: MySQL-gebruikers kunnen worden gekoppeld aan een specifiek host-adres, en mijn gebruiker mocht simpelweg niet verbinden vanaf het VPN-subnet.
Om zeker te weten welk subnet mijn VPN-client kreeg toegewezen, checkte ik dit direct op de Mac:
ifconfig | grep "inet 192"
Dat gaf een adres binnen 192.168.55.0/24 — consistent bij meerdere verbindingen. Dat subnet bleek afkomstig van UniFi’s Teleport-functie (WireGuard-gebaseerd), een aparte VPN-optie los van de klassieke L2TP VPN Server die in de UniFi-interface stond geconfigureerd met een ander subnet (192.168.90.0/24). Een goede les: niet elke VPN-optie in je router-interface is per se degene die je daadwerkelijk gebruikt — controleer het daadwerkelijk toegewezen IP altijd zelf, in plaats van te vertrouwen op wat de UI toont voor een andere dienst.
Stap 3: de MySQL-gebruiker aanpassen voor het juiste subnet
Met het subnet bekend, was de fix in essentie eenvoudig: een MySQL-gebruiker aanmaken (of aanpassen) die verbindingen accepteert vanaf het hele VPN-subnet, in plaats van slechts één los IP-adres:
CREATE USER 'thuis-mac'@'192.168.55.%' IDENTIFIED BY 'sterk_wachtwoord';
GRANT ALL PRIVILEGES ON *.* TO 'thuis-mac'@'192.168.55.%';
FLUSH PRIVILEGES;
Het %-wildcard in het host-gedeelte matcht elk IP binnen dat bereik (192.168.55.0 t/m 192.168.55.255), zodat de login blijft werken ook als de VPN-client een net iets ander adres binnen datzelfde subnet uitdeelt bij een volgende sessie.
Stap 4: een kleine misser onderweg (en hoe je die oplost)
Bij het uitvoeren liep ik tegen een herkenbaar foutje aan: de eerste CREATE USER-poging voerde ik iets te snel uit, nog zonder het juiste wachtwoord ingevuld. Toen ik het daarna alsnog met het juiste wachtwoord probeerde, kreeg ik:
Error Code: 1396. Operation CREATE USER failed for 'thuis-mac'@'192.168.55.%'
Deze foutcode betekent simpelweg dat de gebruiker al bestaat — de eerste (onvolledige) poging was namelijk al geslaagd. De oplossing is dan niet nóg een keer CREATE USER, maar het wachtwoord alsnog instellen op de bestaande gebruiker:
ALTER USER 'thuis-mac'@'192.168.55.%' IDENTIFIED BY 'sterk_wachtwoord';
FLUSH PRIVILEGES;
Wil je liever helemaal opnieuw beginnen, dan kan dat ook door de gebruiker eerst te verwijderen:
DROP USER 'thuis-mac'@'192.168.55.%';
CREATE USER 'thuis-mac'@'192.168.55.%' IDENTIFIED BY 'sterk_wachtwoord';
GRANT ALL PRIVILEGES ON *.* TO 'thuis-mac'@'192.168.55.%';
FLUSH PRIVILEGES;
Belangrijkste lessen
Een paar inzichten die breder toepasbaar zijn dan alleen dit specifieke geval:
- Als het ene protocol werkt en het andere niet, is het zelden de VPN-tunnel zelf. Kijk naar poort- en dienst-specifieke restricties.
- Onderscheid netwerkfouten van rechten-fouten. Een timeout wijst op firewall/routing; een expliciete “access denied” betekent dat het verkeer aankomt maar wordt geweigerd op applicatieniveau.
- Vertrouw niet blind op VPN-instellingen in een dashboard als je meerdere VPN-opties hebt (zoals Teleport naast een klassieke VPN Server) — check het daadwerkelijk toegewezen IP-adres altijd zelf.
- MySQL-gebruikers zijn gebonden aan een host-patroon, niet alleen aan een wachtwoord. Een wildcard-subnet (192.168.55.%) is vaak praktischer dan een los IP, zeker als een VPN-client niet steeds exact hetzelfde adres krijgt.
- Error 1396 betekent “gebruiker bestaat al” — vaak het gevolg van een eerdere, onvolledige poging. ALTER USER is dan je vriend, niet nóg een CREATE USER.
Met deze aanpassing werkte de verbinding via VPN direct, zonder verdere wijzigingen aan firewall-regels of MySQL’s bind-address. Soms is het probleem dus kleiner dan het aanvankelijk lijkt — je moet alleen eerst weten waar je moet kijken.