Configuring MariaDB External Access on Siemens IOT2050

David Krause9 min read
Industrial NetworkingSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

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 GRANTS returns 'user'@'%', so the user account appears correctly provisioned.
  • netstat -ant | grep 3306 shows 127.0.0.1:3306 LISTEN rather than 0.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.

Safety note: Exposing MariaDB on a plant-floor gateway without TLS, a non-loopback bind restriction, or a firewall rule places production data on the shop-floor network. Apply the hardening steps in section 9 before connecting any non-trusted client.

2. Prerequisites

Before modifying the database configuration, confirm the following:

  1. Hardware: SIMATIC IOT2050 (6ES7647-0BA00-0YA2 basic, or 6ES7647-0BB00-0YA2 advanced variant) with at least 4 GB microSD or onboard eMMC.
  2. Firmware / Image: IOT2050_Example_Image_V1.2.1 (Debian 5.10.64) or SIMATIC Industrial OS V1.x. Verify with:
    uname -r → expected 5.10.64-v7l+ for the Example Image.
  3. MariaDB version: 10.5.x or 10.11.x. Verify with:
    mariadb --version
  4. Root or sudo privileges: Required to edit files under /etc/mysql/ and restart the systemd unit.
  5. Backup: Snapshot the SD card (dd if=/dev/mmcblk0 of=iot2050-backup.img bs=4M status=progress) before modifying configuration files.
  6. 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

  1. Open an SSH session on the IOT2050 with a privileged user:
    ssh iotuser@<iot2050_ip>
  2. Switch to root:
    sudo -i
  3. Open the configuration file:
    nano /etc/mysql/mariadb.conf.d/50-server.cnf
  4. Locate the line beginning with bind-address. Replace 127.0.0.1 with 0.0.0.0:
    bind-address = 0.0.0.0
  5. Save with Ctrl+O, confirm the filename, and exit with Ctrl+X.
Binding options: 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
Restrict the source address range whenever possible. A 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:

  1. Switch to socket authentication for local root if remote root access is not required:
    ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket;
  2. Remove anonymous accounts:
    DELETE FROM mysql.user WHERE User='';
    FLUSH PRIVILEGES;
  3. Disable the test database:
    DROP DATABASE test;
  4. Enforce strong passwords via validate_password plugin or external PAM.
  5. Enable TLS by setting ssl = ON in 50-server.cnf and requiring it on user accounts:
    ALTER USER 'usr1'@'192.168.20.%' REQUIRE SSL;
  6. Restrict bind-address to the management IP instead of 0.0.0.0 if only one interface should serve the database.
  7. Rotate the password after commissioning and document the change in the plant's change-log.
  8. 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

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.

Back to blog