1. Problem Overview
The SIMATIC IOT2050 is a rugged industrial IoT gateway based on the TI ARM Cortex-A53 SoC (formerly Sitara) and shipped from Siemens with a Debian-based Example Image or the SIMATIC Industrial OS. Out of the box, both variants install MariaDB with a bind-address of 127.0.0.1 so that the database is only reachable from the local host. This is the correct default for a hardened industrial appliance, but it blocks every external SCADA, MES, or engineering client from opening a TCP/3306 session to the gateway.
Typical symptom pattern observed in the field:
- Node-RED, Mosquitto, and locally executed shell scripts can read/write the database without error.
- An external PC, HMI, or PLC client receives
ERROR 2003 (HY000): Can't connect to MySQL server on 'iot2050' (110)or(10060)on Windows, depending on the OS that issues the connection. -
SHOW GRANTSreturns'user'@'%', so the user account appears correctly provisioned. -
netstat -ant | grep 3306shows127.0.0.1:3306 LISTENrather than0.0.0.0:3306 LISTEN.
This article documents the corrective procedure, the verification sequence, and the security hardening steps that should be applied after external access is opened.
2. Prerequisites
Before modifying the database configuration, confirm the following:
- Hardware: SIMATIC IOT2050 (6ES7647-0BA00-0YA2 basic, or 6ES7647-0BB00-0YA2 advanced variant) with at least 4 GB microSD or onboard eMMC.
-
Firmware / Image: IOT2050_Example_Image_V1.2.1 (Debian 5.10.64) or SIMATIC Industrial OS V1.x. Verify with:
uname -r→ expected5.10.64-v7l+for the Example Image. -
MariaDB version: 10.5.x or 10.11.x. Verify with:
mariadb --version -
Root or sudo privileges: Required to edit files under
/etc/mysql/and restart the systemd unit. -
Backup: Snapshot the SD card (
dd if=/dev/mmcblk0 of=iot2050-backup.img bs=4M status=progress) before modifying configuration files. -
Network reachability: The remote client must be able to ARP/ping the IOT2050 management interface. Confirm with
ping <iot2050_ip>from the external PC.
3. Root Cause: Loopback-Bound MariaDB Listener
The MariaDB server included in the Siemens Example Image follows Debian's distribution defaults. The Debian packaging installs a server configuration under /etc/mysql/mariadb.conf.d/50-server.cnf with the directive:
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address = 127.0.0.1
Because the listener is bound exclusively to the loopback interface, the kernel never places the TCP socket on the external NIC. Any inbound SYN packet destined to port 3306 on the IOT2050's management address is dropped before the userspace mysqld process sees it. User grants for 'user'@'%' are therefore irrelevant: the connection never reaches the authentication layer.
This is documented behavior in Debian's mariadb-server package and in upstream MariaDB Server configuration guidelines. The official MariaDB documentation states that the listener address must be set to 0.0.0.0 (all IPv4 interfaces), a specific interface IP, or * to accept non-localhost clients.
4. Step-by-Step Procedure
4.1 Edit the MariaDB Server Configuration
- Open an SSH session on the IOT2050 with a privileged user:
ssh iotuser@<iot2050_ip> - Switch to root:
sudo -i - Open the configuration file:
nano /etc/mysql/mariadb.conf.d/50-server.cnf - Locate the line beginning with
bind-address. Replace127.0.0.1with0.0.0.0:
bind-address = 0.0.0.0 - Save with Ctrl+O, confirm the filename, and exit with Ctrl+X.
0.0.0.0 accepts connections on every IPv4 interface. To restrict exposure, substitute the management interface IP (for example 192.168.20.50) so only that NIC serves port 3306. The IPv6 equivalent is :: for all interfaces or a specific fe80:: link-local.
4.2 Restart the MariaDB Service
systemctl restart mariadb
systemctl status mariadb --no-pager
Confirm that the unit reports active (running) with no errors. A full IOT2050 reboot is not required, but a reboot (reboot) is acceptable if the application stack tolerates downtime.
5. Verification
5.1 Confirm the Listener is Bound to All Interfaces
netstat -ant | grep 3306
Expected output:
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
On newer systems, use ss -tlnp | grep 3306 instead. The PID/program column should list mysqld or mariadbd.
5.2 Test from the IOT2050 Itself
mariadb -h 127.0.0.1 -u usr1 -p -e "SELECT VERSION();"
This confirms authentication still works locally.
5.3 Test from an External Client
From a Windows client:
telnet 192.168.20.50 3306
mysql -h 192.168.20.50 -P 3306 -u usr1 -p
If telnet shows a banner starting with 5.5.5- (the MariaDB handshake), the TCP path is open. If telnet hangs or returns Connection refused, the bind has not taken effect or a firewall is intercepting traffic.
5.4 Validate Grants from the Server Side
mariadb -u root -p
MariaDB [(none)]> SELECT user, host, plugin FROM mysql.user WHERE user='usr1';
The host column must include % or the specific remote IP, otherwise authentication will still be refused even on an open port.
6. User Account and Host Matching
MariaDB performs authentication based on the tuple (user, host). The host column is compared against the client's source IP by reverse-DNS lookup followed by a forward-resolution check. To avoid DNS-related failures in an industrial environment, prefer IP-literal host entries over wildcard or DNS names.
| Grant Pattern | Matches | Use Case |
|---|---|---|
'usr1'@'%' |
Any client IP | Lab / development only |
'usr1'@'192.168.20.%' |
192.168.20.0/24 | Plant-floor subnet |
'usr1'@'192.168.20.30' |
Single engineering station | Restricted access |
'usr1'@'iot-scada' |
Reverse-DNS resolved host | Not recommended; needs working DNS |
After creating the account, flush the privilege cache:
MariaDB [(none)]> CREATE USER 'usr1'@'192.168.20.%' IDENTIFIED BY 'StrongP@ssw0rd!';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON iotdata.* TO 'usr1'@'192.168.20.%';
MariaDB [(none)]> FLUSH PRIVILEGES;
7. Industrial OS vs Example Image Differences
| Aspect | Example Image V1.2.1 (Debian 5.10.64) | SIMATIC Industrial OS V1.x |
|---|---|---|
| MariaDB package | Pre-installed, listens on 127.0.0.1 | Not pre-installed; install via apt install mariadb-server
|
| Config path | /etc/mysql/mariadb.conf.d/50-server.cnf | Same path after install |
| Default firewall | nftables/iptables inactive | nftables active with default-deny inbound |
| User management | Standard Linux accounts | Siemens user management overlay |
| Update channel | Debian apt repository | Siemens Industrial OS feed |
On the SIMATIC Industrial OS the bind-address change is identical, but you must additionally allow TCP/3306 through the nftables ruleset (section 8).
8. Firewall Configuration
Although the Example Image ships without an active host firewall, real installations frequently run nftables or iptables configured by the system integrator. A common failure mode is that the bind-address is fixed but a rule still drops traffic.
8.1 nftables (Industrial OS default)
nft list ruleset | grep 3306
nft add rule inet filter input tcp dport 3306 ct state new,established ip saddr 192.168.20.0/24 accept
nft list ruleset > /etc/nftables.conf
8.2 iptables (legacy Debian)
iptables -A INPUT -p tcp -s 192.168.20.0/24 --dport 3306 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables-save > /etc/iptables/rules.v4
0.0.0.0/0 ACCEPT rule defeats the purpose of running a host firewall and exposes the database to the entire plant network.
9. Security Hardening
Once MariaDB is reachable on the network, treat the service as production-critical:
-
Switch to socket authentication for local root if remote root access is not required:
ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket; -
Remove anonymous accounts:
DELETE FROM mysql.user WHERE User='';FLUSH PRIVILEGES; -
Disable the test database:
DROP DATABASE test; -
Enforce strong passwords via
validate_passwordplugin or external PAM. -
Enable TLS by setting
ssl = ONin50-server.cnfand requiring it on user accounts:ALTER USER 'usr1'@'192.168.20.%' REQUIRE SSL; -
Restrict bind-address to the management IP instead of
0.0.0.0if only one interface should serve the database. - Rotate the password after commissioning and document the change in the plant's change-log.
- Enable the audit plugin (Server Audit Plugin) for change-tracking on regulated sites.
10. Troubleshooting Matrix
| Symptom | Likely Cause | Diagnostic Command | Resolution |
|---|---|---|---|
| Connection refused from external client |
bind-address still 127.0.0.1 |
netstat -ant | grep 3306 |
Edit 50-server.cnf, restart mariadb |
| Connection times out | Host firewall drops SYN | nft list ruleset |
Add INPUT ACCEPT rule for tcp/3306 |
| ERROR 1045 Access denied for user | User account host mismatch | SELECT user,host FROM mysql.user; |
Recreate user with correct host or IP wildcard |
| ERROR 1130 Host not allowed | Missing grant for client IP | SHOW GRANTS FOR 'usr1'@'%'; |
Run GRANT statement, FLUSH PRIVILEGES |
| Banner received but query fails | Missing privileges on database | SHOW GRANTS FOR current_user(); |
GRANT ALL on target database |
| Works on LAN, fails on WAN/VPN | MTU / fragmentation | ping -M do -s 1472 |
Tune net.ipv4.tcp_mtu_probing=1
|
| DNS resolution in grant fails | Industrial network lacks reverse DNS | getent hosts $(hostname -i) |
Use IP-literal grants instead of hostnames |
11. Performance and Connection-Limit Considerations
Industrial gateways are not database servers. A SIMATIC IOT2050 with 1 GB RAM should be limited to a handful of concurrent external sessions:
SET GLOBAL max_connections = 20;
SET GLOBAL wait_timeout = 300;
For larger client populations, offload the database to a dedicated server and keep the IOT2050 as a thin OPC UA / MQTT edge node. MariaDB's InnoDB buffer pool on the IOT2050 should not exceed 25 percent of physical RAM:
[mariadb]
innodb_buffer_pool_size = 256M
max_connections = 20
12. Backup and Rollback
Before every configuration change, capture a copy of the working file:
cp /etc/mysql/mariadb.conf.d/50-server.cnf /etc/mysql/mariadb.conf.d/50-server.cnf.bak
systemctl restart mariadb
Rollback is then a single line:sed -i 's/bind-address = 0.0.0.0/bind-address = 127.0.0.1/' /etc/mysql/mariadb.conf.d/50-server.cnf && systemctl restart mariadb
13. Official Documentation References
- SIMATIC IOT2050 Product Manual (Siemens Industry Online Support)
- SIMATIC IOT2050 Example Image V1.2.1 Release Notes
- MariaDB Knowledge Base: bind-address Server System Variable
- MariaDB Knowledge Base: Configuring MariaDB for Remote Client Access
- MariaDB Knowledge Base: Securing MariaDB for Production
- Debian mariadb-server Manual Page
Why does Node-RED reach MariaDB but a remote PC does not?
Node-RED runs on the IOT2050 itself, so it connects through the loopback interface. MariaDB's default bind-address = 127.0.0.1 accepts loopback traffic and refuses everything else, regardless of the user grants. Change the bind-address to 0.0.0.0 or to the management interface IP and restart mariadb.
Which file controls the MariaDB bind-address on the IOT2050?
The relevant file in the Example Image is /etc/mysql/mariadb.conf.d/50-server.cnf. Replace bind-address = 127.0.0.1 with bind-address = 0.0.0.0, save, and run systemctl restart mariadb.
Do I still need to recreate the user after changing bind-address?
Yes. Grants are matched against the client IP via the (user, host) tuple. A user created as 'usr1'@'localhost' will be rejected when the client connects from 192.168.20.30. Use 'usr1'@'%' or 'usr1'@'192.168.20.%', then run FLUSH PRIVILEGES;.
Does the IOT2050 ship with a firewall that blocks 3306?
The Example Image V1.2.1 ships without an active host firewall, so the only blocker is the bind-address. SIMATIC Industrial OS uses nftables with default-deny inbound rules, so you must add an explicit ACCEPT rule for tcp/3306 from the trusted subnet.
How do I verify that port 3306 is reachable from outside?
Run netstat -ant | grep 3306 on the IOT2050 and look for 0.0.0.0:3306 LISTEN. From the external client, execute telnet <iot2050_ip> 3306; a successful connection displays the MariaDB handshake banner beginning with 5.5.5-.
Is exposing MariaDB on 0.0.0.0 safe in a plant network?
It is acceptable as long as you restrict grants to known source IPs, enforce TLS with REQUIRE SSL, avoid the 'user'@'%' wildcard in production, and keep the IOT2050 on a segmented OT VLAN with an industrial firewall in front of it.