diff --git a/src/box/lua/info.c b/src/box/lua/info.c
index 55382fd774c99bbd21eadddeafaf3374f3460bdb..e029e0e174be4545cf60a14b6dfef9ff71fd8cfc 100644
--- a/src/box/lua/info.c
+++ b/src/box/lua/info.c
@@ -50,6 +50,7 @@
 #include "box/box.h"
 #include "lua/utils.h"
 #include "fiber.h"
+#include "tt_static.h"
 
 static void
 lbox_pushvclock(struct lua_State *L, const struct vclock *vclock)
@@ -65,6 +66,20 @@ lbox_pushvclock(struct lua_State *L, const struct vclock *vclock)
 	luaL_setmaphint(L, -1); /* compact flow */
 }
 
+static inline void
+lbox_push_replication_error_message(struct lua_State *L, struct error *e,
+				    int idx)
+{
+	lua_pushstring(L, "message");
+	lua_pushstring(L, e->errmsg);
+	lua_settable(L, idx - 2);
+	if (e->saved_errno == 0)
+		return;
+	lua_pushstring(L, "system_message");
+	lua_pushstring(L, strerror(e->saved_errno));
+	lua_settable(L, idx - 2);
+}
+
 static void
 lbox_pushapplier(lua_State *L, struct applier *applier)
 {
@@ -103,11 +118,8 @@ lbox_pushapplier(lua_State *L, struct applier *applier)
 		lua_settable(L, -3);
 
 		struct error *e = diag_last_error(&applier->reader->diag);
-		if (e != NULL) {
-			lua_pushstring(L, "message");
-			lua_pushstring(L, e->errmsg);
-			lua_settable(L, -3);
-		}
+		if (e != NULL)
+			lbox_push_replication_error_message(L, e, -1);
 	}
 }
 
@@ -135,11 +147,8 @@ lbox_pushrelay(lua_State *L, struct relay *relay)
 		lua_settable(L, -3);
 
 		struct error *e = diag_last_error(relay_get_diag(relay));
-		if (e != NULL) {
-			lua_pushstring(L, "message");
-			lua_pushstring(L, e->errmsg);
-			lua_settable(L, -3);
-		}
+		if (e != NULL)
+			lbox_push_replication_error_message(L, e, -1);
 		break;
 	}
 	default: unreachable();
diff --git a/test/replication/gh-4402-info-errno.result b/test/replication/gh-4402-info-errno.result
new file mode 100644
index 0000000000000000000000000000000000000000..661eea38bf3892e8a8caf6c588f01c85696e9cf1
--- /dev/null
+++ b/test/replication/gh-4402-info-errno.result
@@ -0,0 +1,63 @@
+-- test-run result file version 2
+test_run = require('test_run').new()
+ | ---
+ | ...
+
+--
+-- gh-4402: replication info table should contain not only
+-- Tarantool's error, but also a system error (errno's message)
+-- when possible.
+--
+
+box.schema.user.grant('guest', 'replication')
+ | ---
+ | ...
+
+test_run:cmd('create server replica with rpl_master=default, script="replication/replica.lua"')
+ | ---
+ | - true
+ | ...
+test_run:cmd('start server replica')
+ | ---
+ | - true
+ | ...
+i = box.info
+ | ---
+ | ...
+replica_id = i.id % 2 + 1
+ | ---
+ | ...
+d = i.replication[replica_id].downstream
+ | ---
+ | ...
+d ~= nil and d.status == 'follow' or i
+ | ---
+ | - true
+ | ...
+
+test_run:cmd('stop server replica')
+ | ---
+ | - true
+ | ...
+test_run:cmd("cleanup server replica")
+ | ---
+ | - true
+ | ...
+test_run:cmd("delete server replica")
+ | ---
+ | - true
+ | ...
+i = box.info
+ | ---
+ | ...
+d = i.replication[replica_id].downstream
+ | ---
+ | ...
+d ~= nil and d.system_message ~= nil and d.message ~= nil or i
+ | ---
+ | - true
+ | ...
+
+box.schema.user.revoke('guest', 'replication')
+ | ---
+ | ...
diff --git a/test/replication/gh-4402-info-errno.test.lua b/test/replication/gh-4402-info-errno.test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1b2d9d8148ffb3aa26b1ed3b88cc4d9d9131844f
--- /dev/null
+++ b/test/replication/gh-4402-info-errno.test.lua
@@ -0,0 +1,25 @@
+test_run = require('test_run').new()
+
+--
+-- gh-4402: replication info table should contain not only
+-- Tarantool's error, but also a system error (errno's message)
+-- when possible.
+--
+
+box.schema.user.grant('guest', 'replication')
+
+test_run:cmd('create server replica with rpl_master=default, script="replication/replica.lua"')
+test_run:cmd('start server replica')
+i = box.info
+replica_id = i.id % 2 + 1
+d = i.replication[replica_id].downstream
+d ~= nil and d.status == 'follow' or i
+
+test_run:cmd('stop server replica')
+test_run:cmd("cleanup server replica")
+test_run:cmd("delete server replica")
+i = box.info
+d = i.replication[replica_id].downstream
+d ~= nil and d.system_message ~= nil and d.message ~= nil or i
+
+box.schema.user.revoke('guest', 'replication')
diff --git a/test/replication/suite.cfg b/test/replication/suite.cfg
index 13b9131cc815e683b7c2f6e1e842c0b75ee0f1df..0848eecd61eaf8c74a91af6bdf319871b3039610 100644
--- a/test/replication/suite.cfg
+++ b/test/replication/suite.cfg
@@ -11,6 +11,7 @@
     "on_schema_init.test.lua": {},
     "long_row_timeout.test.lua": {},
     "join_without_snap.test.lua": {},
+    "gh-4402-info-errno.test.lua": {},
     "gh-4606-admin-creds.test.lua": {},
     "*": {
         "memtx": {"engine": "memtx"},