diff --git a/CMakeLists.txt b/CMakeLists.txt
index bac4dd4..b286ee2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -248,6 +248,7 @@
 
 check_symbol_exists(chsize io.h HAVE_CHSIZE)
 check_symbol_exists(getrlimit sys/resource.h HAVE_GETRLIMIT)
+check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
 check_symbol_exists(strsep string.h HAVE_STRSEP)
 check_symbol_exists(strtok_r string.h HAVE_STRTOK_R)
 
@@ -431,6 +432,7 @@
     src/compat/compat-daemon.c
     src/compat/compat-dirname.c
     src/compat/compat-gettimeofday.c
+    src/compat/compat-strlcpy.c
     src/compat/compat-strsep.c
     src/compat/compat-strtok_r.c
     src/openvpn/argv.c
@@ -764,6 +766,7 @@
             src/openvpn/platform.c
             src/openvpn/win32-util.c
             src/compat/compat-gettimeofday.c
+            src/compat/compat-strlcpy.c
             src/compat/compat-strsep.c
             src/compat/compat-strtok_r.c
             )
diff --git a/config.h.cmake.in b/config.h.cmake.in
index 8c3088e..483de45 100644
--- a/config.h.cmake.in
+++ b/config.h.cmake.in
@@ -267,6 +267,9 @@
 /* Define to 1 if you have the <string.h> header file. */
 #define HAVE_STRING_H 1
 
+/* Define to 1 if you have the `strlcpy' function. */
+#cmakedefine HAVE_STRLCPY
+
 /* Define to 1 if you have the `strsep' function. */
 #cmakedefine HAVE_STRSEP
 
diff --git a/configure.ac b/configure.ac
index 56109af..ad3f8f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -568,7 +568,7 @@
 	setgroups flock gettimeofday \
 	setsid chdir \
 	chsize ftruncate execve getpeereid basename dirname \
-	epoll_create strsep strtok_r \
+	epoll_create strlcpy strsep strtok_r \
 ])
 
 AC_CHECK_LIB(
diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am
index 22867b3..8b1d44a 100644
--- a/src/compat/Makefile.am
+++ b/src/compat/Makefile.am
@@ -20,5 +20,6 @@
 	compat-basename.c \
 	compat-gettimeofday.c \
 	compat-daemon.c \
+	compat-strlcpy.c \
 	compat-strsep.c \
-	compat-strtok_r.c
\ No newline at end of file
+	compat-strtok_r.c
diff --git a/src/compat/compat-strlcpy.c b/src/compat/compat-strlcpy.c
new file mode 100644
index 0000000..8c1e80a
--- /dev/null
+++ b/src/compat/compat-strlcpy.c
@@ -0,0 +1,52 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2026 OpenVPN Inc <sales@openvpn.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef HAVE_STRLCPY
+#include <string.h>
+
+size_t
+strlcpy(char *dest, const char *src, size_t maxlen)
+{
+    if (maxlen > 0)
+    {
+        strncpy(dest, src, maxlen - 1);
+        dest[maxlen - 1] = 0;
+    }
+    return strlen(src);
+}
+
+size_t
+strlcat(char *dest, const char *src, size_t maxlen)
+{
+    size_t dest_len = strnlen(dest, maxlen);
+    if (maxlen > dest_len)
+    {
+        strncat(dest, src, maxlen - dest_len - 1);
+    }
+    return dest_len + strlen(src);
+}
+
+#endif /* ifndef HAVE_STRLCPY */
diff --git a/src/compat/compat.h b/src/compat/compat.h
index 9e6f95c..4ee9141 100644
--- a/src/compat/compat.h
+++ b/src/compat/compat.h
@@ -56,6 +56,15 @@
 
 #endif
 
+#ifndef HAVE_STRLCPY
+size_t
+strlcpy(char *dest, const char *src, size_t maxlen);
+
+size_t
+strlcat(char *dest, const char *src, size_t maxlen);
+
+#endif
+
 #ifndef HAVE_STRSEP
 char *strsep(char **stringp, const char *delim);
 
diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am
index 5430ecb..38299f5 100644
--- a/tests/unit_tests/openvpn/Makefile.am
+++ b/tests/unit_tests/openvpn/Makefile.am
@@ -54,6 +54,7 @@
 argv_testdriver_SOURCES = test_argv.c \
 	mock_msg.c mock_msg.h test_common.h \
 	mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/platform.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/win32-util.c \
@@ -64,6 +65,7 @@
 buffer_testdriver_SOURCES = test_buffer.c \
 	mock_msg.c mock_msg.h test_common.h \
 	mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/win32-util.c \
 	$(top_srcdir)/src/openvpn/platform.c
 
@@ -74,6 +76,7 @@
 crypto_testdriver_SOURCES = test_crypto.c \
 	mock_msg.c mock_msg.h test_common.h \
 	siphash_openssl.c siphash_openssl.h \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/crypto.c \
 	$(top_srcdir)/src/openvpn/crypto_mbedtls.c \
@@ -94,6 +97,7 @@
 dhcp_testdriver_SOURCES = test_dhcp.c \
 	mock_msg.c mock_msg.h test_common.h \
 	mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/platform.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/win32-util.c
@@ -106,6 +110,7 @@
 	mock_msg.c mock_msg.h test_common.h \
 	mock_management.c \
 	mock_ssl_dependencies.c mock_win32_execve.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/argv.c \
 	$(top_srcdir)/src/openvpn/base64.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
@@ -145,6 +150,7 @@
 packet_id_testdriver_SOURCES = test_packet_id.c \
 	mock_msg.c mock_msg.h test_common.h \
 	mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/otime.c \
 	$(top_srcdir)/src/openvpn/packet_id.c \
@@ -158,6 +164,7 @@
 	@TEST_CFLAGS@
 pkt_testdriver_LDFLAGS = @TEST_LDFLAGS@
 pkt_testdriver_SOURCES = test_pkt.c mock_msg.c mock_msg.h mock_win32_execve.c test_common.h \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/argv.c \
 	$(top_srcdir)/src/openvpn/base64.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
@@ -190,6 +197,7 @@
 tls_crypt_testdriver_SOURCES = test_tls_crypt.c \
 	mock_msg.c mock_msg.h test_common.h \
 	mock_win32_execve.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/argv.c \
 	$(top_srcdir)/src/openvpn/base64.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
@@ -212,6 +220,7 @@
 networking_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(top_srcdir)/src/openvpn \
 	$(OPTIONAL_CRYPTO_LIBS)
 networking_testdriver_SOURCES = test_networking.c mock_msg.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/networking_sitnl.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/crypto.c \
@@ -230,6 +239,7 @@
 options_parse_testdriver_SOURCES = test_options_parse.c \
 	mock_msg.c mock_msg.h test_common.h \
 	mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/options_parse.c \
 	$(top_srcdir)/src/openvpn/options_util.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
@@ -243,6 +253,7 @@
 	$(OPTIONAL_CRYPTO_LIBS)
 
 provider_testdriver_SOURCES = test_provider.c mock_msg.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/xkey_helper.c \
 	$(top_srcdir)/src/openvpn/xkey_provider.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
@@ -259,6 +270,7 @@
 	$(OPTIONAL_CRYPTO_LIBS) -lcrypt32 -lncrypt
 cryptoapi_testdriver_SOURCES = test_cryptoapi.c mock_msg.c \
 	pkey_test_utils.c cert_data.h \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/xkey_helper.c \
 	$(top_srcdir)/src/openvpn/xkey_provider.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
@@ -278,6 +290,7 @@
 pkcs11_testdriver_SOURCES = test_pkcs11.c \
 	mock_msg.c test_common.h \
 	pkey_test_utils.c cert_data.h mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/xkey_helper.c \
 	$(top_srcdir)/src/openvpn/xkey_provider.c \
 	$(top_srcdir)/src/openvpn/argv.c \
@@ -300,6 +313,7 @@
 
 auth_token_testdriver_SOURCES = test_auth_token.c \
 	mock_msg.c test_common.h \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/crypto.c \
 	$(top_srcdir)/src/openvpn/crypto_epoch.c \
@@ -320,6 +334,7 @@
 
 user_pass_testdriver_SOURCES = test_user_pass.c \
 	mock_msg.c test_common.h \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/console.c \
 	$(top_srcdir)/src/openvpn/env_set.c \
@@ -339,6 +354,7 @@
 
 ncp_testdriver_SOURCES = test_ncp.c \
 	mock_msg.c test_common.h \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/crypto.c \
 	$(top_srcdir)/src/openvpn/crypto_epoch.c \
@@ -362,6 +378,7 @@
 mbuf_testdriver_SOURCES = test_mbuf.c \
 	mock_msg.c test_common.h  \
 	mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/win32-util.c \
 	$(top_srcdir)/src/openvpn/platform.c \
@@ -377,6 +394,7 @@
 	test_schedule.c test_schedule.h \
 	mock_msg.c test_common.h  \
 	mock_get_random.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/options_util.c \
 	$(top_srcdir)/src/openvpn/ssl_util.c \
@@ -402,6 +420,7 @@
 	mock_msg.c \
 	mock_get_random.c \
 	mock_push_dependencies.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/platform.c \
 	$(top_srcdir)/src/openvpn/options_util.c \
@@ -419,6 +438,7 @@
 	mock_msg.c test_common.h  \
 	mock_get_random.c \
 	mock_management.c \
+	$(top_srcdir)/src/compat/compat-strlcpy.c \
 	$(top_srcdir)/src/openvpn/buffer.c \
 	$(top_srcdir)/src/openvpn/win32-util.c \
 	$(top_srcdir)/src/openvpn/platform.c \
