diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua
index 67d5f9f60106ca47f2f6894aa96b3e1af588361f..266e2aad60552e3474bd0a9cd5d3a396081a3174 100644
--- a/src/lua/bsdsocket.lua
+++ b/src/lua/bsdsocket.lua
@@ -565,29 +565,27 @@ end
 
 local function readline_check(self, eols, limit)
     local rbuf = self.rbuf
-    if rbuf == nil then
-        return nil
-    end
     if string.len(rbuf) == 0 then
         return nil
     end
 
     local shortest
-    for i, eol in pairs(eols) do
-        if string.len(rbuf) >= string.len(eol) then
-            local data = string.match(rbuf, "^(.-" .. eol .. ")")
-            if data ~= nil then
-                if string.len(data) > limit then
-                    data = string.sub(data, 1, limit)
-                end
-                if shortest == nil then
-                    shortest = data
-                elseif #shortest > #data then
-                    shortest = data
-                end
+    for i, eol in ipairs(eols) do
+        local data = string.match(rbuf, "^(.-" .. eol .. ")")
+        if data ~= nil then
+            if string.len(data) > limit then
+                data = string.sub(data, 1, limit)
+            end
+            if shortest == nil then
+                shortest = data
+            elseif #shortest > #data then
+                shortest = data
             end
         end
     end
+    if shortest == nil and #rbuf >= limit then
+        return string.sub(rbuf, limit)
+    end
     return shortest
 end
 
@@ -597,6 +595,9 @@ local function readline(self, limit, eol, timeout)
     end
 
     self._errno = nil
+    if limit == 0 then
+        return ''
+    end
     local data = readline_check(self, eol, limit)
     if data ~= nil then
         self.rbuf = string.sub(self.rbuf, string.len(data) + 1)
diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result
index 9f0b5a15c4cb434bba7c7dbee7151cd665a85d0b..1b589404087da3ac81e3cf90760790c63401d92b 100644
--- a/test/box/bsdsocket.result
+++ b/test/box/bsdsocket.result
@@ -1120,6 +1120,74 @@ lua server:close()
 ---
  - true
 ...
+lua body = "a 10\nb 15\nx"
+---
+...
+lua remaining = #body
+---
+...
+lua server = box.socket.tcp_server("unix/", "%s", function(s) s:write(body) s:read() end)
+---
+...
+lua client = box.socket.tcp_connect("unix/", "%s")
+---
+...
+lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"})
+---
+...
+lua buf == "a 10\n"
+---
+ - true
+...
+lua remaining = remaining - #buf
+---
+...
+lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"})
+---
+...
+lua buf == "b 15\n"
+---
+ - true
+...
+lua remaining = remaining - #buf
+---
+...
+lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"})
+---
+...
+lua buf == "x"
+---
+ - true
+...
+lua remaining = remaining - #buf
+---
+...
+lua remaining == 0
+---
+ - true
+...
+lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"})
+---
+...
+lua buf == ""
+---
+ - true
+...
+lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"})
+---
+...
+lua buf == ""
+---
+ - true
+...
+lua client:close()
+---
+ - true
+...
+lua server:close()
+---
+ - true
+...
 lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 'ip')
 ---
 ...
diff --git a/test/box/bsdsocket.test b/test/box/bsdsocket.test
index 72907dbbf9d9220d05ce2d2892601e1301adff87..706061dd313a868df537dbab55bae0ba958ee8b4 100644
--- a/test/box/bsdsocket.test
+++ b/test/box/bsdsocket.test
@@ -360,6 +360,28 @@ exec admin "lua client:read(123)"
 exec admin "lua client:close()"
 exec admin "lua server:close()"
 
+## gh-658: socket:read() incorrectly handles size and delimiter together
+exec admin 'lua body = "a 10\\nb 15\\nx"'
+exec admin 'lua remaining = #body'
+exec admin 'lua server = box.socket.tcp_server("unix/", "%s", function(s) s:write(body) s:read() end)'.format(path)
+exec admin 'lua client = box.socket.tcp_connect("unix/", "%s")'.format(path)
+exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})'
+exec admin 'lua buf == "a 10\\n"'
+exec admin 'lua remaining = remaining - #buf'
+exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})'
+exec admin 'lua buf == "b 15\\n"'
+exec admin 'lua remaining = remaining - #buf'
+exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})'
+exec admin 'lua buf == "x"'
+exec admin 'lua remaining = remaining - #buf'
+exec admin 'lua remaining == 0'
+exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})'
+exec admin 'lua buf == ""'
+exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})'
+exec admin 'lua buf == ""'
+exec admin 'lua client:close()'
+exec admin 'lua server:close()'
+
 # Test that socket is closed on GC
 exec admin "lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 'ip')"
 exec admin "lua s:bind('unix/', '{}')".format(path)