diff --git a/src/coeio.cc b/src/coeio.cc
index c9ee8635f9020d223f02104979d294a5d526aee0..c15cfabf232a97112f512dc7fe7e36862a42a174 100644
--- a/src/coeio.cc
+++ b/src/coeio.cc
@@ -174,8 +174,7 @@ coio_task(struct coio_task *task, coio_task_cb func,
 	if (fiber_yield_timeout(timeout) && !task->complete) {
 		/* timed out. */
 		task->fiber = NULL;
-		errno = ETIMEDOUT;
-		return -1;
+		tnt_raise(TimedOut);
 	}
 
 	return task->base.result;
@@ -334,11 +333,8 @@ coio_getaddrinfo(const char *host, const char *port,
 	/* do resolving */
 	/* coio_task() don't throw. */
 	if (coio_task(&task->base, getaddrinfo_cb, getaddrinfo_free_cb,
-		       timeout) == -1) {
-		/* timed out */
-		errno = ETIMEDOUT;
-		return rc;
-	}
+		       timeout) == -1)
+		tnt_raise(TimedOut);
 
 	rc = task->rc;
 	*res = task->result;
diff --git a/src/coio.cc b/src/coio.cc
index b9e60eeb6dc44b3d1efb8484d7354cc4d21063b0..7ebce0994ffdaf8d85939903f715ca48d4897e94 100644
--- a/src/coio.cc
+++ b/src/coio.cc
@@ -96,10 +96,8 @@ coio_connect_addr(struct ev_io *coio, struct sockaddr *addr,
 	bool is_timedout = coio_fiber_yield_timeout(coio, timeout);
 	ev_io_stop(loop, coio);
 	fiber_testcancel();
-	if (is_timedout) {
-		errno = ETIMEDOUT;
-		return -1;
-	}
+	if (is_timedout)
+		tnt_raise(TimedOut);
 	int error = EINPROGRESS;
 	socklen_t sz = sizeof(error);
 	sio_getsockopt(coio->fd, SOL_SOCKET, SO_ERROR,
@@ -203,12 +201,8 @@ coio_connect_timeout(struct ev_io *coio, struct uri *uri, struct sockaddr *addr,
 	    hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV|AI_PASSIVE;
 	    hints.ai_protocol = 0;
 	    int rc = coio_getaddrinfo(host, service, &hints, &ai, delay);
-	    if (rc != 0) {
-		    if (errno == ETIMEDOUT)
-			    return -1; /* timeout */
+	    if (rc != 0)
 		    tnt_raise(SocketError, -1, "getaddrinfo");
-	    }
-
 	}
 	auto addrinfo_guard = make_scoped_guard([=] {
 		if (!uri->host_hint) freeaddrinfo(ai);
@@ -275,10 +269,8 @@ coio_accept(struct ev_io *coio, struct sockaddr *addr,
 		 */
 		bool is_timedout = coio_fiber_yield_timeout(coio, delay);
 		fiber_testcancel();
-		if (is_timedout) {
-			errno = ETIMEDOUT;
-			tnt_raise(SocketError, coio->fd, "accept");
-		}
+		if (is_timedout)
+			tnt_raise(TimedOut);
 		coio_timeout_update(start, &delay);
 	}
 }
@@ -290,7 +282,7 @@ coio_accept(struct ev_io *coio, struct sockaddr *addr,
  * and sets errno to 0.
  * Can read up to bufsiz bytes.
  *
- * @retval the number of bytes read, sets the errno to ETIMEDOUT or 0.
+ * @retval the number of bytes read.
  */
 ssize_t
 coio_read_ahead_timeout(struct ev_io *coio, void *buf, size_t sz,
@@ -335,10 +327,8 @@ coio_read_ahead_timeout(struct ev_io *coio, void *buf, size_t sz,
 		bool is_timedout = coio_fiber_yield_timeout(coio,
 							    delay);
 		fiber_testcancel();
-		if (is_timedout) {
-			errno = ETIMEDOUT;
-			return sz - to_read;
-		}
+		if (is_timedout)
+			tnt_raise(TimedOut);
 		coio_timeout_update(start, &delay);
 	}
 }
@@ -430,10 +420,8 @@ coio_write_timeout(struct ev_io *coio, const void *buf, size_t sz,
 							    delay);
 		fiber_testcancel();
 
-		if (is_timedout) {
-			errno = ETIMEDOUT;
-			return sz - towrite;
-		}
+		if (is_timedout)
+			tnt_raise(TimedOut);
 		coio_timeout_update(start, &delay);
 	}
 }
@@ -502,10 +490,8 @@ coio_writev_timeout(struct ev_io *coio, struct iovec *iov, int iovcnt,
 		bool is_timedout = coio_fiber_yield_timeout(coio, delay);
 		fiber_testcancel();
 
-		if (is_timedout) {
-			errno = ETIMEDOUT;
-			return total;
-		}
+		if (is_timedout)
+			tnt_raise(TimedOut);
 		coio_timeout_update(start, &delay);
 	}
 	return total;
@@ -515,7 +501,6 @@ coio_writev_timeout(struct ev_io *coio, struct iovec *iov, int iovcnt,
  * Send up to sz bytes to a UDP socket.
  * Return the number of bytes sent.
  *
- * @retval  0, errno = ETIMEDOUT timeout
  * @retval  n  the number of bytes written
  */
 ssize_t
@@ -549,10 +534,8 @@ coio_sendto_timeout(struct ev_io *coio, const void *buf, size_t sz, int flags,
 		bool is_timedout = coio_fiber_yield_timeout(coio,
 							    delay);
 		fiber_testcancel();
-		if (is_timedout) {
-			errno = ETIMEDOUT;
-			return 0;
-		}
+		if (is_timedout)
+			tnt_raise(TimedOut);
 		coio_timeout_update(start, &delay);
 	}
 }
@@ -561,7 +544,6 @@ coio_sendto_timeout(struct ev_io *coio, const void *buf, size_t sz, int flags,
  * Read a datagram up to sz bytes from a socket, with a timeout.
  *
  * @retval   0, errno = 0   eof
- * @retval   0, errno = ETIMEDOUT timeout
  * @retvl    n              number of bytes read
  */
 ssize_t
@@ -596,10 +578,8 @@ coio_recvfrom_timeout(struct ev_io *coio, void *buf, size_t sz, int flags,
 		bool is_timedout = coio_fiber_yield_timeout(coio,
 							    delay);
 		fiber_testcancel();
-		if (is_timedout) {
-			errno = ETIMEDOUT;
-			return 0;
-		}
+		if (is_timedout)
+			tnt_raise(TimedOut);
 		coio_timeout_update(start, &delay);
 	}
 }
diff --git a/src/exception.cc b/src/exception.cc
index c3e8a38b187e54ec751a84d8d92b32259fcc9885..8cee67ea5d1abb6bc2117b41d383b8eacddac8ef 100644
--- a/src/exception.cc
+++ b/src/exception.cc
@@ -165,3 +165,12 @@ OutOfMemory::OutOfMemory(const char *file, unsigned line,
 		 "Failed to allocate %u bytes in %s for %s",
 		 (unsigned) amount, allocator, object);
 }
+
+const struct type type_TimedOut =
+	make_type("TimedOut", &type_SystemError);
+
+TimedOut::TimedOut(const char *file, unsigned line)
+	: SystemError(&type_OutOfMemory, file, line)
+{
+	m_errno = ETIMEDOUT;
+}
diff --git a/src/exception.h b/src/exception.h
index 4497f75ac45c8b255f3caa83d453d9b894c312dc..6cb1b8c7b51f3968fd403bde845d7af830c7f083 100644
--- a/src/exception.h
+++ b/src/exception.h
@@ -138,6 +138,12 @@ class OutOfMemory: public SystemError {
 		    const char *object);
 };
 
+extern const struct type type_TimedOut;
+class TimedOut: public SystemError {
+public:
+	TimedOut(const char *file, unsigned line);
+};
+
 /**
  * Diagnostics Area - a container for errors and warnings
  */
diff --git a/src/latch.h b/src/latch.h
index 2d56399126c476fd6c649d209d9882096c1a6125..449ce3e4b8d730c6270b9f1b22c51b9714231d5b 100644
--- a/src/latch.h
+++ b/src/latch.h
@@ -110,7 +110,6 @@ latch_lock_timeout(struct latch *l, ev_tstamp timeout)
 		}
 		timeout -= ev_now(loop()) - start;
 		if (timeout <= 0) {
-			errno = ETIMEDOUT;
 			result = 1;
 			break;
 		}
diff --git a/src/lua/bsdsocket.cc b/src/lua/bsdsocket.cc
index ae4bbcb2484bdc90ffd6539fcf070602276c6ce3..75c9fa4b7b56af7050263dd95040e2595c62bae3 100644
--- a/src/lua/bsdsocket.cc
+++ b/src/lua/bsdsocket.cc
@@ -665,7 +665,12 @@ lbox_bsdsocket_getaddrinfo(struct lua_State *L)
 		lua_pop(L, 1);
 	}
 
-	int dns_res = coio_getaddrinfo(host, port, &hints, &result, timeout);
+	int dns_res = 0;
+	try {
+		dns_res = coio_getaddrinfo(host, port, &hints, &result, timeout);
+	} catch (TimedOut *e) {
+		dns_res = 1;
+	}
 	lua_pop(L, 2);	/* host, port */
 
 	if (dns_res != 0) {