diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua
index 7eaeafdbe7cfd80fb204403cc0ea1d3216330374..966fba483ce452a683999307a17b92f038e6150e 100644
--- a/src/lua/bsdsocket.lua
+++ b/src/lua/bsdsocket.lua
@@ -2,6 +2,7 @@
 
 local TIMEOUT_INFINITY      = 500 * 365 * 86400
 local LIMIT_INFINITY = 4294967295
+local READAHEAD = 16380
 
 local ffi = require('ffi')
 local boxerrno = require('errno')
@@ -178,7 +179,7 @@ end
 
 socket_methods.sysread = function(self, size)
     local fd = check_socket(self)
-    size = size or 4096
+    size = size or READAHEAD
     self._errno = nil
     local buf = ffi.new('char[?]', size)
     local res = ffi.C.read(fd, buf, size)
@@ -554,7 +555,7 @@ local function readchunk(self, limit, timeout)
 
     if self.rlen >= limit then
         self._errno = nil
-        local data = string.sub(self.rbuf, self.rpos, self.rpos + limit)
+        local data = string.sub(self.rbuf, self.rpos, self.rpos - 1 + limit)
         self.rlen = self.rlen - limit
         self.rpos = self.rpos + limit
         return data
@@ -570,7 +571,7 @@ local function readchunk(self, limit, timeout)
         timeout = timeout - ( fiber.time() - started )
 
         local to_read
-        if limit ~= LIMIT_INFINITY then
+        if limit ~= LIMIT_INFINITY and limit > READAHEAD then
             to_read = limit - self.rlen
         end
         local data = self:sysread(to_read)
@@ -582,7 +583,7 @@ local function readchunk(self, limit, timeout)
                 limit = self.rlen
             end
             if self.rlen >= limit then
-               data = string.sub(self.rbuf, self.rpos, self.rpos + limit)
+               data = string.sub(self.rbuf, self.rpos, self.rpos - 1 + limit)
                self.rlen = self.rlen - limit
                self.rpos = self.rpos + limit
                return data
@@ -618,7 +619,7 @@ local function readline_check(self, eols, limit)
         end
     end
     if shortest == nil and self.rlen >= limit then
-        shortest = string.sub(self.rbuf, self.rpos, self.rpos + limit)
+        shortest = string.sub(self.rbuf, self.rpos, self.rpos - 1 + limit)
     end
     if shortest ~= nil then
         local len = string.len(shortest)
@@ -653,7 +654,7 @@ local function readline(self, limit, eol, timeout)
         timeout = timeout - ( fiber.time() - started )
 
         local to_read
-        if limit ~= LIMIT_INFINITY then
+        if limit ~= LIMIT_INFINITY and limit > READAHEAD then
             to_read = limit - self.rlen
         end
         local data = self:sysread(to_read)
diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result
index 9f37c31cb49eb6d2436528906465a557cf4a9fad..948aeb702425a96a89cae5efc1d5d53797c203c1 100644
--- a/test/box/bsdsocket.result
+++ b/test/box/bsdsocket.result
@@ -70,7 +70,7 @@ s:close()
 s:close()
 
 ---
-- error: 'builtin/socket.lua:82: attempt to use closed socket'
+- error: 'builtin/socket.lua:83: attempt to use closed socket'
 ...
 LISTEN = require('uri').parse(box.cfg.listen)
 ---
@@ -279,7 +279,7 @@ s:getsockopt('SOL_SOCKET', 'SO_DEBUG')
 ...
 s:setsockopt('SOL_SOCKET', 'SO_ACCEPTCONN', 1)
 ---
-- error: 'builtin/socket.lua:356: Socket option SO_ACCEPTCONN is read only'
+- error: 'builtin/socket.lua:357: Socket option SO_ACCEPTCONN is read only'
 ...
 s:getsockopt('SOL_SOCKET', 'SO_RCVBUF') > 32
 ---
@@ -1030,7 +1030,7 @@ ch:get(1)
 ...
 s:error()
 ---
-- error: 'builtin/socket.lua:82: attempt to use closed socket'
+- error: 'builtin/socket.lua:83: attempt to use closed socket'
 ...
 -- random port
 port = 33123