diff --git a/extra/exports b/extra/exports
index 59ebb3499c3f3ca63f320457c973f1a10e3cd0a8..e348e9b5a2b918ddde719905b9681d774ded6604 100644
--- a/extra/exports
+++ b/extra/exports
@@ -13,6 +13,8 @@ guava
 random_bytes
 fiber_time
 fiber_time64
+fiber_clock
+fiber_clock64
 tarantool_lua_slab_cache
 ibuf_create
 ibuf_reinit
diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua
index c612ab8a025fb17aeba4d9f6fa88e4f55239e47d..5cccc70723db736ccb69c57b5d359c33690ae261 100644
--- a/src/box/lua/net_box.lua
+++ b/src/box/lua/net_box.lua
@@ -12,7 +12,7 @@ local trigger  = require('internal.trigger')
 
 local band          = bit.band
 local max           = math.max
-local fiber_time    = fiber.time
+local fiber_clock   = fiber.clock
 local fiber_self    = fiber.self
 local ibuf_decode   = msgpack.ibuf_decode
 
@@ -177,10 +177,10 @@ local function create_transport(host, port, user, password, callback)
 
     -- FYI: [] on a string is valid
     local function wait_state(target_state, timeout)
-        local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY)
+        local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY)
         repeat until state == target_state or target_state[state] or
                      is_final_state[state] or
-                     not state_cond:wait(max(0, deadline - fiber_time()))
+                     not state_cond:wait(max(0, deadline - fiber_clock()))
         return state == target_state or target_state[state] or false
     end
 
@@ -223,7 +223,7 @@ local function create_transport(host, port, user, password, callback)
         if state ~= 'active' then
             return last_errno or E_NO_CONNECTION, last_error
         end
-        local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY)
+        local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY)
         -- alert worker to notify it of the queued outgoing data;
         -- if the buffer wasn't empty, assume the worker was already alerted
         if send_buf:size() == 0 then
@@ -239,7 +239,7 @@ local function create_transport(host, port, user, password, callback)
         request.buffer = buffer
         requests[id] = request
         repeat
-            local timeout = max(0, deadline - fiber_time())
+            local timeout = max(0, deadline - fiber_clock())
             if not state_cond:wait(timeout) then
                 requests[id] = nil
                 return E_TIMEOUT, 'Timeout exceeded'
@@ -321,12 +321,12 @@ local function create_transport(host, port, user, password, callback)
                 return nil, hdr, body_rpos, body_end
             end
         end
-        local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY)
+        local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY)
         local err, extra = send_and_recv(required, timeout)
         if err then
             return err, extra
         end
-        return send_and_recv_iproto(max(0, deadline - fiber_time()))
+        return send_and_recv_iproto(max(0, deadline - fiber_clock()))
     end
 
     local function send_and_recv_console(timeout)
@@ -350,13 +350,13 @@ local function create_transport(host, port, user, password, callback)
     local console_sm, iproto_auth_sm, iproto_schema_sm, iproto_sm, error_sm
 
     protocol_sm = function ()
-        local tm_begin, tm = fiber.time(), callback('fetch_connect_timeout')
+        local tm_begin, tm = fiber.clock(), callback('fetch_connect_timeout')
         connection = socket.tcp_connect(host, port, tm)
         if connection == nil then
             return error_sm(E_NO_CONNECTION, errno.strerror(errno()))
         end
         local size = IPROTO_GREETING_SIZE
-        local err, msg = send_and_recv(size, tm - (fiber.time() - tm_begin))
+        local err, msg = send_and_recv(size, tm - (fiber.clock() - tm_begin))
         if err then
             return error_sm(err, msg)
         end
@@ -696,7 +696,7 @@ function remote_methods:_request(method, opts, ...)
     local deadline = nil
     if opts and opts.timeout then
         -- conn.space:request(, { timeout = timeout })
-        deadline = fiber_time() + opts.timeout
+        deadline = fiber_clock() + opts.timeout
     else
         -- conn:timeout(timeout).space:request()
         -- @deprecated since 1.7.4
@@ -705,10 +705,10 @@ function remote_methods:_request(method, opts, ...)
     local buffer = opts and opts.buffer
     local err, res
     repeat
-        local timeout = deadline and max(0, deadline - fiber_time())
+        local timeout = deadline and max(0, deadline - fiber_clock())
         if self.state ~= 'active' then
             wait_state('active', timeout)
-            timeout = deadline and max(0, deadline - fiber_time())
+            timeout = deadline and max(0, deadline - fiber_clock())
         end
         err, res = perform_request(timeout, buffer, method,
                                    self.schema_version, ...)
@@ -738,7 +738,7 @@ function remote_methods:ping(opts)
         -- conn:timeout(timeout):ping()
         -- @deprecated since 1.7.4
         local deadline = self._deadlines[fiber_self()]
-        timeout = deadline and max(0, deadline - fiber_time())
+        timeout = deadline and max(0, deadline - fiber_clock())
                             or (opts and opts.timeout)
     end
     local err = self._transport.perform_request(timeout, nil, 'ping',
@@ -790,7 +790,7 @@ function remote_methods:wait_state(state, timeout)
     check_remote_arg(self, 'wait_state')
     if timeout == nil then
         local deadline = self._deadlines[fiber_self()]
-        timeout = deadline and max(0, deadline-fiber_time())
+        timeout = deadline and max(0, deadline - fiber_clock())
     end
     return self._transport.wait_state(state, timeout)
 end
@@ -806,7 +806,7 @@ function remote_methods:timeout(timeout)
                  "please use space:<request>(..., {timeout = t}) instead.")
     end
     -- Sic: this is broken by design
-    self._deadlines[fiber_self()] = (timeout and fiber_time() + timeout)
+    self._deadlines[fiber_self()] = (timeout and fiber_clock() + timeout)
     return self
 end
 
@@ -909,9 +909,9 @@ function console_methods:eval(line, timeout)
     local transport = self._transport
     local pr = transport.perform_request
     if self.state ~= 'active' then
-        local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY)
+        local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY)
         transport.wait_state('active', timeout)
-        timeout = max(0, deadline - fiber_time())
+        timeout = max(0, deadline - fiber_clock())
     end
     if self.protocol == 'Binary' then
         local loader = 'return require("console").eval(...)'
diff --git a/src/fiber.c b/src/fiber.c
index 5f093922214b7dc658d486d33bb046004bba6a8c..298c7ab2f2ae7dbe17231c9f1bc2d68074a22c29 100644
--- a/src/fiber.c
+++ b/src/fiber.c
@@ -354,6 +354,18 @@ fiber_time64(void)
 	return (uint64_t) ( ev_now(loop()) * 1000000 + 0.5 );
 }
 
+double
+fiber_clock(void)
+{
+	return ev_monotonic_now(loop());
+}
+
+uint64_t
+fiber_clock64(void)
+{
+	return (uint64_t) ( ev_monotonic_now(loop()) * 1000000 + 0.5 );
+}
+
 /**
  * Move current fiber to the end of ready fibers list and switch to next
  */
diff --git a/src/fiber.h b/src/fiber.h
index f1610fc39ea6652219d4f663b966986c0abadd81..0d0930cf593359799c76bfe384958652fcd0dbcb 100644
--- a/src/fiber.h
+++ b/src/fiber.h
@@ -290,16 +290,32 @@ fiber_is_cancelled();
 
 /**
  * Report loop begin time as double (cheap).
+ * Uses real time clock.
  */
 API_EXPORT double
 fiber_time(void);
 
 /**
  * Report loop begin time as 64-bit int.
+ * Uses real time clock.
  */
 API_EXPORT uint64_t
 fiber_time64(void);
 
+/**
+ * Report loop begin time as double (cheap).
+ * Uses monotonic clock.
+ */
+API_EXPORT double
+fiber_clock(void);
+
+/**
+ * Report loop begin time as 64-bit int.
+ * Uses monotonic clock.
+ */
+API_EXPORT uint64_t
+fiber_clock64(void);
+
 /**
  * Reschedule fiber to end of event loop cycle.
  */
diff --git a/src/lua/fiber.lua b/src/lua/fiber.lua
index 20bdbbfead71402f372f797de133e27d405228cb..8712ee0d682aab4eda2be2cc7bcbff830c86987d 100644
--- a/src/lua/fiber.lua
+++ b/src/lua/fiber.lua
@@ -7,6 +7,10 @@ double
 fiber_time(void);
 uint64_t
 fiber_time64(void);
+double
+fiber_clock(void);
+uint64_t
+fiber_clock64(void);
 ]]
 local C = ffi.C
 
@@ -18,6 +22,16 @@ local function fiber_time64()
     return C.fiber_time64()
 end
 
+local function fiber_clock()
+    return tonumber(C.fiber_clock())
+end
+
+local function fiber_clock64()
+    return C.fiber_clock64()
+end
+
 fiber.time = fiber_time
 fiber.time64 = fiber_time64
+fiber.clock = fiber_clock
+fiber.clock64 = fiber_clock64
 return fiber
diff --git a/src/lua/socket.lua b/src/lua/socket.lua
index 84343ee4bc41dc297ae931b2c8ed152443953500..9270ada98f4f142fc0613d8893fd297b192ab9b6 100644
--- a/src/lua/socket.lua
+++ b/src/lua/socket.lua
@@ -600,9 +600,8 @@ local function read(self, limit, timeout, check, ...)
         return data
     end
 
-    local started = fiber.time()
     while timeout > 0 do
-        local started = fiber.time()
+        local started = fiber.clock()
 
         assert(rbuf:size() < limit)
         local to_read = math.min(limit - rbuf:size(), buffer.READAHEAD)
@@ -635,7 +634,7 @@ local function read(self, limit, timeout, check, ...)
         if timeout <= 0 then
             break
         end
-        timeout = timeout - ( fiber.time() - started )
+        timeout = timeout - ( fiber.clock() - started )
     end
     self._errno = boxerrno.ETIMEDOUT
     return nil
@@ -675,7 +674,7 @@ socket_methods.write = function(self, octets, timeout)
         return 0
     end
 
-    local started = fiber.time()
+    local started = fiber.clock()
     while true do
         local written = syswrite(self, p, e - p)
         if written == 0 then
@@ -690,7 +689,7 @@ socket_methods.write = function(self, octets, timeout)
             return nil
         end
 
-        timeout = timeout - (fiber.time() - started)
+        timeout = timeout - (fiber.clock() - started)
         if timeout <= 0 or not self:writable(timeout) then
             break
         end
@@ -957,7 +956,7 @@ local function tcp_connect(host, port, timeout)
             family = 'PF_UNIX', type = 'SOCK_STREAM' }, timeout)
     end
     local timeout = timeout or TIMEOUT_INFINITY
-    local stop = fiber.time() + timeout
+    local stop = fiber.clock() + timeout
     local dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM',
         protocol = 'tcp' })
     if dns == nil or #dns == 0 then
@@ -965,7 +964,7 @@ local function tcp_connect(host, port, timeout)
         return nil
     end
     for i, remote in pairs(dns) do
-        timeout = stop - fiber.time()
+        timeout = stop - fiber.clock()
         if timeout <= 0 then
             boxerrno(boxerrno.ETIMEDOUT)
             return nil