diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua
index e7aa926cda7ada49175a24c5132020c859babdab..3259a5921bc5240b4586afa749e5b2e19e9d2a5b 100644
--- a/src/lua/bsdsocket.lua
+++ b/src/lua/bsdsocket.lua
@@ -6,6 +6,8 @@ local ffi = require('ffi')
 local boxerrno = require('errno')
 local internal = require('socket')
 local fiber = require('fiber')
+local fio = require('fio')
+local log = require('log')
 
 ffi.cdef[[
     struct socket {
@@ -980,7 +982,7 @@ local function tcp_server_loop(server, s, addr)
         fiber.create(tcp_server_handler, server, sc, from)
     end
     if addr.family == 'AF_UNIX' and addr.port then
-        os.remove(addr.port) -- remove unix socket
+        fio.unlink(addr.port) -- remove unix socket
     end
 end
 
@@ -988,6 +990,43 @@ local function tcp_server_usage()
     error('Usage: socket.tcp_server(host, port, handler | opts)')
 end
 
+local function tcp_server_bind(s, addr)
+    if s:bind(addr.host, addr.port) then
+        return true
+    end
+
+    if addr.family ~= 'AF_UNIX' then
+        return false
+    end
+
+    if boxerrno() ~= boxerrno.EADDRINUSE then
+        return false
+    end
+
+    local save_errno = boxerrno()
+
+    local sc = tcp_connect(addr.host, addr.port)
+    if sc ~= nil then
+        sc:close()
+        boxerrno(save_errno)
+        return false
+    end
+
+    if boxerrno() ~= boxerrno.ECONNREFUSED then
+        boxerrno(save_errno)
+        return false
+    end
+
+    log.info("tcp_server: remove dead UNIX socket: %s", addr.port)
+    if not fio.unlink(addr.port) then
+        log.warn("tcp_server: %s", boxerrno.strerror())
+        boxerrno(save_errno)
+        return false
+    end
+    return s:bind(addr.host, addr.port)
+end
+
+
 local function tcp_server(host, port, opts, timeout)
     local server = {}
     if type(opts) == 'function' then
@@ -1025,7 +1064,7 @@ local function tcp_server(host, port, opts, timeout)
             else
                 s:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', 1) -- ignore error
             end
-            if not s:bind(addr.host, addr.port) or not s:listen(backlog) then
+            if not tcp_server_bind(s, addr) or not s:listen(backlog) then
                 local save_errno = boxerrno()
                 s:close()
                 boxerrno(save_errno)
diff --git a/src/lua/init.cc b/src/lua/init.cc
index 02ca2146cb47f870ab66c5b64c5115acda175cda..02fa51d7e6f357c9db52882451932aa0264b0a3b 100644
--- a/src/lua/init.cc
+++ b/src/lua/init.cc
@@ -94,11 +94,11 @@ static const char *lua_modules[] = {
 	"uuid", uuid_lua,
 	"log", log_lua,
 	"uri", uri_lua,
+	"fio", fio_lua,
 	"socket", bsdsocket_lua,
 	"net.box", box_net_box_lua,
 	"console", console_lua,
 	"tap", tap_lua,
-	"fio", fio_lua,
 	"help.en_US", help_en_US_lua,
 	"help", help_lua,
 	NULL
@@ -293,9 +293,9 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv)
 	tarantool_lua_fiber_init(L);
 	tarantool_lua_ipc_init(L);
 	tarantool_lua_errno_init(L);
+	tarantool_lua_fio_init(L);
 	tarantool_lua_bsdsocket_init(L);
 	tarantool_lua_pickle_init(L);
-	tarantool_lua_fio_init(L);
 	luaopen_msgpack(L);
 	lua_pop(L, 1);
 	luaopen_yaml(L);
diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result
index 043ac1e95ce91274c569ca22e00fb7a3f63a7a39..e59baf99d259b3e51bfd1b508028aa22a7d525d2 100644
--- a/test/box/bsdsocket.result
+++ b/test/box/bsdsocket.result
@@ -279,7 +279,7 @@ s:getsockopt('SOL_SOCKET', 'SO_DEBUG')
 ...
 s:setsockopt('SOL_SOCKET', 'SO_ACCEPTCONN', 1)
 ---
-- error: 'builtin/socket.lua:341: Socket option SO_ACCEPTCONN is read only'
+- error: 'builtin/socket.lua:343: Socket option SO_ACCEPTCONN is read only'
 ...
 s:getsockopt('SOL_SOCKET', 'SO_RCVBUF') > 32
 ---
@@ -1433,3 +1433,45 @@ yaml.decode(yaml.encode(s)).fd == s:fd()
 s = nil
 ---
 ...
+-- start AF_UNIX server with dead socket exists
+path = '/tmp/tarantool-test-socket'
+---
+...
+s = socket('AF_UNIX', 'SOCK_STREAM', 0)
+---
+...
+s:bind('unix/', path)
+---
+- true
+...
+s:close()
+---
+- true
+...
+s = socket('AF_UNIX', 'SOCK_STREAM', 0)
+---
+...
+{ s:bind('unix/', path), errno.strerror() }
+---
+- - false
+  - Address already in use
+...
+s:close()
+---
+- true
+...
+s = socket.tcp_server('unix/', path, function() end)
+---
+...
+s ~= nil
+---
+- true
+...
+s:close()
+---
+- true
+...
+fio.stat(path) == nil
+---
+- true
+...
diff --git a/test/box/bsdsocket.test.lua b/test/box/bsdsocket.test.lua
index faf0346c4099676777570ff8f70f3c88caa69d16..9081ad5a352d20d485bb9013481f03448d9476e1 100644
--- a/test/box/bsdsocket.test.lua
+++ b/test/box/bsdsocket.test.lua
@@ -482,3 +482,18 @@ s.waiters
 json.decode(json.encode(s)).fd == s:fd()
 yaml.decode(yaml.encode(s)).fd == s:fd()
 s = nil
+
+-- start AF_UNIX server with dead socket exists
+path = '/tmp/tarantool-test-socket'
+s = socket('AF_UNIX', 'SOCK_STREAM', 0)
+s:bind('unix/', path)
+s:close()
+
+s = socket('AF_UNIX', 'SOCK_STREAM', 0)
+{ s:bind('unix/', path), errno.strerror() }
+s:close()
+
+s = socket.tcp_server('unix/', path, function() end)
+s ~= nil
+s:close()
+fio.stat(path) == nil