diff --git a/.travis.yml b/.travis.yml
index a3197a2cec61380bdf9a161331f69564f8cb2a3a..e828daa083980d5f49d9a8351f3228c9369adfb7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,7 +23,7 @@ before_script:
 
 install:
   - sudo apt-get update > /dev/null
-  - sudo apt-get -q install binutils-dev python-daemon python-yaml uuid-dev
+  - sudo apt-get -q install binutils-dev python-daemon python-yaml
   - sudo apt-get -q install libmysqlclient-dev libpq-dev postgresql-server-dev-all
 
 script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d107dacfd43ab6c5ac02e9f1fde42df9b5dce439..424d296f848ee6302457e797b3c7a36e28d69b6c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -79,6 +79,7 @@ endif()
 check_function_exists(open_memstream HAVE_OPEN_MEMSTREAM)
 check_function_exists(fmemopen HAVE_FMEMOPEN)
 check_function_exists(funopen HAVE_FUNOPEN)
+check_function_exists(uuidgen HAVE_UUIDGEN)
 
 #
 # Some versions of GNU libc define non-portable __libc_stack_end
@@ -305,13 +306,6 @@ include(BuildLibYAML)
 libyaml_build()
 add_dependencies(build_bundled_libs yaml)
 
-#
-# LibUUID
-#
-
-set(LIBUUID_FIND_REQUIRED ON)
-find_package(LibUUID)
-
 #
 # Third-Party misc
 #
diff --git a/README.md b/README.md
index ca3d201b4837fa2bf21d910ae5f899414c9a9b83..223a68b012f233464ca4dcae0cfe63331e14c9b2 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,6 @@ CMake is used for configuration management.
 The build depends on the following external libraries:
 
 - libreadline and libreadline-dev
-- uuid and uuid-dev.
 - GNU bfd (part of GNU binutils).
 
 Please follow these steps to compile Tarantool:
diff --git a/cmake/BuildLibEIO.cmake b/cmake/BuildLibEIO.cmake
index 582c96fe17887e4a8c93819a596b027b971d71ad..3f4c59a924f242d9e8f7920e53ee3a7efa4ba5aa 100644
--- a/cmake/BuildLibEIO.cmake
+++ b/cmake/BuildLibEIO.cmake
@@ -5,6 +5,7 @@ macro(libeio_build)
 
     set(eio_compile_flags "${eio_compile_flags} -Wno-unused-result")
     set(eio_compile_flags "${eio_compile_flags} -Wno-dangling-else")
+    set(eio_compile_flags "${eio_compile_flags} -Wno-unused-value")
     set(eio_compile_flags "${eio_compile_flags} -DENABLE_BUNDLED_LIBEIO=1")
     set(eio_compile_flags "${eio_compile_flags} -DEIO_STACKSIZE=0")
 
diff --git a/cmake/FindLibUUID.cmake b/cmake/FindLibUUID.cmake
deleted file mode 100644
index 0db8ae7e5e155eb0b371a02909566c449b2ff255..0000000000000000000000000000000000000000
--- a/cmake/FindLibUUID.cmake
+++ /dev/null
@@ -1,31 +0,0 @@
-if(NOT LIBUUID_FOUND)
-    find_path(LIBUUID_INCLUDE_DIR
-        NAMES uuid.h
-        PATH_SUFFIXES uuid
-    )
-    if (LIBUUID_INCLUDE_DIR)
-        if (NOT LIBUUID_FIND_QUIETLY)
-            message(STATUS "Found libuuid includes: ${LIBUUID_INCLUDE_DIR}")
-        endif ()
-        set(LIBUUID_INCLUDE_DIRS ${LIBUUID_INCLUDE_DIR})
-        check_library_exists(uuid uuid_is_null "" HAVE_LIBUUID_LINUX)
-        if (HAVE_LIBUUID_LINUX)
-            if (NOT LIBUUID_FIND_QUIETLY)
-                message(STATUS "Found libuuid library: ${LIBUUID_LIBRARIES}")
-            endif ()
-            set(LIBUUID_FOUND ON)
-            set(LIBUUID_LIBRARIES uuid)
-        else()
-            check_library_exists(c uuid_is_nil "" HAVE_LIBUUID_BSD)
-            if (HAVE_LIBUUID_BSD)
-                set(LIBUUID_FOUND ON)
-            elseif (LIBUUID_FIND_REQUIRED)
-                message(FATAL_ERROR "Could not find uuid libraries")
-            endif()
-    endif()
-    elseif(LIBUUID_FIND_REQUIRED)
-         message(FATAL_ERROR "Could not find uuid development files")
-    endif()
-endif (NOT LIBUUID_FOUND)
-
-mark_as_advanced(LIBUUID_LIBRARIES LIBUUID_INCLUDE_DIRS)
diff --git a/debian/control b/debian/control
index a75e10a13487acba64280c921aa5710728623e52..c54bb43cb8fb2355f1167b3300ef5544458bd119 100644
--- a/debian/control
+++ b/debian/control
@@ -7,8 +7,7 @@ Build-Depends: cdbs, debhelper (>= 8),
  libncurses5-dev,
  libiberty-dev | binutils-dev,
  libmysqlclient-dev,
- libpq-dev,
- uuid-dev
+ libpq-dev
 Section: database
 Standards-Version: 3.9.5
 Homepage: http://tarantool.org/
diff --git a/doc/user/tutorial.xml b/doc/user/tutorial.xml
index b563003b482056fc852d6c014aefbcad491f27b1..184c5d3fbd40a040a82d63c682deedc1a5dec16b 100644
--- a/doc/user/tutorial.xml
+++ b/doc/user/tutorial.xml
@@ -283,7 +283,6 @@ ones unless you intend to work on the documentation.</para>
  <listitem><para>binutils-dev or binutils-devel       # contains GNU bfd for printing stack traces</para></listitem>
  <listitem><para> gcc or clang                        # see above</para></listitem>
  <listitem><para> git                                 # see above</para></listitem>
- <listitem><para> uuid-dev                            # for uuid_* functions and replication</para></listitem>
  <listitem><para> cmake                               # see above</para></listitem>
  <listitem><para> libreadline-dev                     # for interactive mode</para></listitem>
  <listitem><para> libncurses5-dev or ncurses-devel    # see above</para></listitem>
@@ -459,7 +458,7 @@ the server (but not the documentation), and run tests after build.
 
 <para>
 To build with SUSE 13.1, the steps are as described above, except that the appropriate YaST2 package names are:
-binutils-devel, libuuid-devel, cmake, ncurses-devel, lynx, jing, libxml2-devel, docbook_5, saxon, libxslt-devel.
+binutils-devel, cmake, ncurses-devel, lynx, jing, libxml2-devel, docbook_5, saxon, libxslt-devel.
 The python connector can be installed with <code>sudo easy_install pip</code> and <code>sudo pip install tarantool</code>.
 </para>
 
diff --git a/extra/rpm/tarantool.rpm.spec.in b/extra/rpm/tarantool.rpm.spec.in
index c7dc52640d1b37615eae9ed193d86b62b21d364b..b241071d92c97f844c075078ae061a30778965f3 100644
--- a/extra/rpm/tarantool.rpm.spec.in
+++ b/extra/rpm/tarantool.rpm.spec.in
@@ -23,12 +23,6 @@ BuildRequires: gcc >= 4.5
 BuildRequires: binutils-devel
 %endif
 
-%if 0%{?rhel} < 6 && 0%{?rhel} > 0
-BuildRequires: e2fsprogs-devel
-%else
-BuildRequires: libuuid-devel
-%endif
-
 %if 0%{?fedora} > 0
 BuildRequires: perl-podlators
 %endif
@@ -45,11 +39,6 @@ Vendor: tarantool.org
 License: BSD
 Requires: %{?scl_prefix}tarantool-debuginfo = @RPM_PACKAGE_VERSION@-@RPM_PACKAGE_RELEASE@
 Requires: readline
-%if 0%{?rhel} <= 5 && 0%{?rhel} > 0
-Requires: e2fsprogs-libs
-%else
-Requires: libuuid
-%endif
 URL: http://tarantool.org
 Source0: @RPM_PACKAGE_SOURCE_FILE_NAME@
 %description
diff --git a/src/box/cluster.cc b/src/box/cluster.cc
index a5bf9664222f4f2c677b2c33d5e426d72bd2fd1d..48f4f6293162fc621d6b6dda725d1ae4f23ea427 100644
--- a/src/box/cluster.cc
+++ b/src/box/cluster.cc
@@ -53,7 +53,7 @@ cluster_add_server(const tt_uuid *server_uuid, uint32_t server_id)
 	/* Add server */
 	vclock_add_server(&r->vclock, server_id);
 
-	if (tt_uuid_cmp(&r->server_uuid, server_uuid) == 0) {
+	if (tt_uuid_is_equal(&r->server_uuid, server_uuid)) {
 		/* Assign local server id */
 		assert(r->server_id == 0);
 		r->server_id = server_id;
diff --git a/src/box/log_io.cc b/src/box/log_io.cc
index c0e719e38aba3fc773d03ef1d349300550a51bd5..69e6d1660d96a257229c9f05d4e026eaeb7aeef4 100644
--- a/src/box/log_io.cc
+++ b/src/box/log_io.cc
@@ -709,7 +709,7 @@ log_io_verify_meta(struct log_io *l, const tt_uuid *server_uuid)
 	}
 
 	if (server_uuid != NULL && !tt_uuid_is_nil(server_uuid) &&
-	    tt_uuid_cmp(server_uuid, &l->server_uuid)) {
+	    !tt_uuid_is_equal(server_uuid, &l->server_uuid)) {
 		say_error("%s: invalid server uuid", l->filename);
 		return -1;
 	}
diff --git a/src/box/replication.cc b/src/box/replication.cc
index 81c8300b78790e7b05e3cd1767f06939ef0cdb82..8b410d13f09d47c5979b0ca100743d97a6856716 100644
--- a/src/box/replication.cc
+++ b/src/box/replication.cc
@@ -249,7 +249,7 @@ replication_subscribe(int fd, struct iproto_header *packet)
 	 * replica connect, and refuse a connection from a replica
 	 * which belongs to a different cluster.
 	 */
-	if (tt_uuid_cmp(&uu, &cluster_id) != 0) {
+	if (!tt_uuid_is_equal(&uu, &cluster_id)) {
 		tnt_raise(ClientError, ER_CLUSTER_ID_MISMATCH,
 			  tt_uuid_str(&uu), tt_uuid_str(&cluster_id));
 	}
diff --git a/src/find_path.c b/src/find_path.c
index f0767238056c83c328b25558d62380ed5d7dc6e5..749596573d466f8fbe11c683cbae1675cb0e5816 100644
--- a/src/find_path.c
+++ b/src/find_path.c
@@ -21,7 +21,7 @@ find_path(const char *argv0)
 		return path;
 
 	char buf[PATH_MAX];
-	uint32_t size = PATH_MAX - 1;
+	size_t size = PATH_MAX - 1;
 	if (argv0[0] == '/')
 		snprintf(buf, size, "%s", argv0);
 	else {
@@ -35,7 +35,8 @@ find_path(const char *argv0)
 		snprintf(buf, size, "%s", getexecname());
 		rc = 0;
 #elif defined(__APPLE__)
-		rc = _NSGetExecutablePath(buf, &size);
+		uint32_t usize = size;
+		rc = _NSGetExecutablePath(buf, &usize);
 #endif
 		if (rc == -1)
 			snprintf(buf, sizeof(buf) - 1, "%s", getenv("_"));
diff --git a/src/iproto.cc b/src/iproto.cc
index 06a237cafcdb8d6aee5c3f815574921d89950cc0..ad52bc05ada65fe67fee61ab860347d227567581 100644
--- a/src/iproto.cc
+++ b/src/iproto.cc
@@ -745,13 +745,12 @@ iproto_request_new(struct iproto_connection *con,
 }
 
 const char *
-iproto_greeting(int *salt)
+iproto_greeting(const char *salt)
 {
 	static __thread char greeting[IPROTO_GREETING_SIZE + 1];
 	char base64buf[SESSION_SEED_SIZE * 4 / 3 + 5];
 
-	base64_encode((char *) salt, SESSION_SEED_SIZE,
-		      base64buf, sizeof(base64buf));
+	base64_encode(salt, SESSION_SEED_SIZE, base64buf, sizeof(base64buf));
 	snprintf(greeting, sizeof(greeting),
 		 "Tarantool %-20s %-32s\n%-63s\n",
 		 tarantool_version(), custom_proc_title, base64buf);
diff --git a/src/lib/bit/bit.c b/src/lib/bit/bit.c
index b4686dcaa3b17b0c2f4ffecb05192a34d6f0355c..0ebf555919ee166d6e614886a4ccd34da6367f0f 100644
--- a/src/lib/bit/bit.c
+++ b/src/lib/bit/bit.c
@@ -68,6 +68,9 @@ bit_rotr_u32(uint32_t x, int r);
 extern inline uint64_t
 bit_rotr_u64(uint64_t x, int r);
 
+extern inline uint16_t
+bswap_u16(uint16_t x);
+
 extern inline uint32_t
 bswap_u32(uint32_t x);
 
diff --git a/src/lib/bit/bit.h b/src/lib/bit/bit.h
index b0eaa71c90941fac9673ce60549f2123dbb0d3a3..7ed64c9b570e8e305959dbbe1196ec026191737c 100644
--- a/src/lib/bit/bit.h
+++ b/src/lib/bit/bit.h
@@ -317,6 +317,20 @@ bit_rotr_u64(uint64_t x, int r)
 	return ((x >> r) | (x << (64 - r)));
 }
 
+/**
+ * @copydoc bswap_u32
+ */
+inline uint16_t
+bswap_u16(uint16_t x)
+{
+#if defined(HAVE_BUILTIN_BSWAP16)
+	return __builtin_bswap16(x);
+#else /* !defined(HAVE_BUILTIN_BSWAP16) */
+	return	((x << 8) & UINT16_C(0xff00)) |
+		((x >> 8) & UINT16_C(0x00ff));
+#endif
+}
+
 /**
  * @brief Returns a byte order swapped integer @a x.
  * This function does not take into account host architecture
diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua
index 487f867b72c71802fd67a601bd7f2460b8be5070..06be8295d4a2ea84f70e691161991e924f6388b6 100644
--- a/src/lua/bsdsocket.lua
+++ b/src/lua/bsdsocket.lua
@@ -925,9 +925,29 @@ local function tcp_connect(host, port, timeout)
                 break
             end
 
-            if s:writable(timeout) then
-                boxerrno(0)
-                return s
+            while true do
+
+                if s:writable(timeout) then
+                    if s:peer(self) ~= nil then
+                        boxerrno(0)
+                        return s
+
+                    elseif boxerrno() ~= boxerrno.EAGAIN then
+                        break
+                    end
+
+                    timeout = timeout - (boxfiber.time() - started)
+                    started = boxfiber.time()
+
+                    if timeout <= 0 then
+                        s:close()
+                        break
+                    end
+
+                else
+                    break
+                end
+
             end
         end
 
diff --git a/src/lua/uuid.lua b/src/lua/uuid.lua
index c1d0b921c0b3226c0dfc72f1d7307bde19dabedf..cc91363c029e322a656c7af45a11c407c3f66681 100644
--- a/src/lua/uuid.lua
+++ b/src/lua/uuid.lua
@@ -4,34 +4,131 @@ local ffi = require("ffi")
 local builtin = ffi.C
 
 ffi.cdef[[
-        /* from <uuid/uuid.h> */
-        typedef unsigned char uuid_t[16];
-        void uuid_generate(uuid_t out);
+struct tt_uuid {
+    uint32_t time_low;
+    uint16_t time_mid;
+    uint16_t time_hi_and_version;
+    uint8_t clock_seq_hi_and_reserved;
+    uint8_t clock_seq_low;
+    uint8_t node[6];
+};
 
-        /* from libc */
-        int snprintf(char *str, size_t size, const char *format, ...);
+void
+tt_uuid_create(struct tt_uuid *uu);
+int
+tt_uuid_from_string(const char *in, struct tt_uuid *uu);
+void
+tt_uuid_to_string(const struct tt_uuid *uu, char *out);
+void
+tt_uuid_bswap(struct tt_uuid *uu);
+bool
+tt_uuid_is_nil(const struct tt_uuid *uu);
+bool
+tt_uuid_is_equal(const struct tt_uuid *lhs, const struct tt_uuid *rhs);
+char *
+tt_uuid_str(const struct tt_uuid *uu);
+extern const struct tt_uuid uuid_nil;
 ]]
 
-local uuid_bin = function()
-    local uuid = ffi.new('uuid_t')
-    builtin.uuid_generate(uuid)
-    return ffi.string(uuid, 16)
+local uuid_t = ffi.typeof('struct tt_uuid')
+local UUID_STR_LEN = 36
+local UUID_LEN = ffi.sizeof(uuid_t)
+local uuidbuf = ffi.new(uuid_t)
+
+local uuid_tostring = function(uu)
+    return ffi.string(builtin.tt_uuid_str(uu), UUID_STR_LEN)
+end
+
+local uuid_fromstr = function(str)
+    if type(str) ~= 'string' then
+        error("fromstr(str)")
+    end
+    local uu = ffi.new(uuid_t)
+    local rc = builtin.tt_uuid_from_string(str, uu)
+    if rc ~= 0 then
+        return nil
+    end
+    return uu
+end
+
+local need_bswap = function(order)
+    if order == nil or order == 'l' or order == 'h' or order == 'host' then
+        return false
+    elseif order == 'b' or order == 'n' or order == 'network' then
+        return true
+    else
+        error('invalid byteorder, valid is l, b, h, n')
+    end
+end
+
+local uuid_tobin = function(uu, byteorder)
+    if need_bswap(byteorder) then
+        if uu ~= uuidbuf then
+            ffi.copy(uuidbuf, uu, UUID_LEN)
+        end
+        builtin.tt_uuid_bswap(uuidbuf)
+        return ffi.string(ffi.cast('char *', uuidbuf), UUID_LEN)
+    end
+    return ffi.string(ffi.cast('char *', uu), UUID_LEN)
+end
+
+local uuid_frombin = function(bin, byteorder)
+    if type(bin) ~= 'string' or #bin ~= UUID_LEN then
+        error("frombin(bin, [byteorder])")
+    end
+    local uu = ffi.new(uuid_t)
+    ffi.copy(uu, bin, UUID_LEN)
+    if need_bswap(byteorder) then
+        builtin.tt_uuid_bswap(uu)
+    end
+    return uu
 end
 
-local uuid_hex = function()
-    local uuid = ffi.new('uuid_t')
-    builtin.uuid_generate(uuid)
-    local uuid_hex = ffi.new('char[33]')
-    for i = 0,ffi.sizeof('uuid_t'),1 do
-        builtin.snprintf(uuid_hex + i * 2, 3, "%02x",
-            ffi.cast('unsigned int',uuid[i]))
+local uuid_isnil = function(uu)
+    return builtin.tt_uuid_is_nil(uu)
+end
+
+local uuid_eq = function(lhs, rhs)
+    if not ffi.istype(uuid_t, rhs) then
+        return false
     end
-    return ffi.string(uuid_hex, 32)
+    return builtin.tt_uuid_is_equal(lhs, rhs)
+end
+
+local uuid_new = function()
+    local uu = ffi.new(uuid_t)
+    builtin.tt_uuid_create(uu)
+    return uu
+end
+
+local uuid_new_bin = function(byteorder)
+    builtin.tt_uuid_create(uuidbuf)
+    return uuid_tobin(uuidbuf, byteorder)
 end
+local uuid_new_str = function()
+    builtin.tt_uuid_create(uuidbuf)
+    return uuid_tostring(uuidbuf)
+end
+
+local uuid_mt = {
+    __tostring = uuid_tostring;
+    __eq = uuid_eq;
+    __index = {
+        isnil = uuid_isnil;
+        bin   = uuid_tobin;    -- binary host byteorder
+        str   = uuid_tostring; -- RFC4122 string
+    }
+}
+
+ffi.metatype(uuid_t, uuid_mt)
 
 return setmetatable({
-    bin = uuid_bin,
-    hex = uuid_hex
+    NULL        = builtin.uuid_nil;
+    new         = uuid_new;
+    fromstr     = uuid_fromstr;
+    frombin     = uuid_frombin;
+    bin         = uuid_new_bin;   -- optimized shortcut for new():bin()
+    str         = uuid_new_str;   -- optimized shortcut for new():str()
 }, {
-    __call = uuid_bin
+    __call = uuid_new; -- shortcut for new()
 })
diff --git a/src/random.c b/src/random.c
index 914e631b3a4e0414e6490dea29624661dbb040e2..2b4e6679a942de2dd7b9662305904635c952658a 100644
--- a/src/random.c
+++ b/src/random.c
@@ -30,22 +30,68 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <unistd.h>
 #include <stdlib.h>
 
-#ifdef __linux__
-#define DEV_RANDOM "/dev/urandom"
-#else
-#define DEV_RANDOM "/dev/random"
-#endif
+static int rfd;
 
 void
 random_init(void)
 {
-	int fd = open(DEV_RANDOM, O_RDONLY);
-	long int seed;
-	read(fd, &seed, sizeof(seed));
-	close(fd);
+	int seed;
+	rfd = open("/dev/urandom", O_RDONLY);
+	if (rfd == -1)
+		rfd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+	if (rfd == -1) {
+		struct timeval tv;
+		gettimeofday(&tv, 0);
+		seed = (getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec;
+		goto srand;
+	}
+
+	int flags = fcntl(rfd, F_GETFD);
+	if (flags != -1)
+		fcntl(rfd, F_SETFD, flags | FD_CLOEXEC);
+
+	read(rfd, &seed, sizeof(seed));
+srand:
 	srandom(seed);
 	srand(seed);
 }
+
+void
+random_free(void)
+{
+	if (rfd == -1)
+		return;
+	close(rfd);
+}
+
+void
+random_bytes(char *buf, size_t size)
+{
+	size_t generated = 0;
+
+	if (rfd == -1)
+		goto rand;
+
+	int attempt = 0;
+	while (generated < size) {
+		ssize_t n = read(rfd, buf + generated, size - generated);
+		if (n <= 0) {
+			if (attempt++ > 5)
+				break;
+			continue;
+		}
+		generated += n;
+		attempt = 0;
+	}
+rand:
+	/* fill remaining bytes with PRNG */
+	generated -= generated % sizeof(int);
+	while (generated < size) {
+		*(int *)(buf + generated) = rand();
+		generated += sizeof(int);
+	}
+}
diff --git a/src/random.h b/src/random.h
index 98cd0e5e4ec16716882f5ec495d2a0285c04c888..6f9e8597ef026a95717801974192e294807c4d6d 100644
--- a/src/random.h
+++ b/src/random.h
@@ -28,12 +28,21 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
+#include <stddef.h>
+
 #if defined(__cplusplus)
 extern "C" {
 #endif
 void
 random_init(void);
 
+void
+random_free(void);
+
+void
+random_bytes(char *buf, size_t size);
+
 #if defined(__cplusplus)
 }
 #endif /* extern "C" */
diff --git a/src/session.cc b/src/session.cc
index 529ceeebcdc4ab2984fb1395daff4625eba744fd..7e3d8e0e30c93bccd0d394ab066567e30cd379fd 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -33,6 +33,7 @@
 #include "assoc.h"
 #include "trigger.h"
 #include "exception.h"
+#include "random.h"
 #include <sys/socket.h>
 
 static struct mh_i32ptr_t *session_registry;
@@ -67,8 +68,7 @@ session_create(int fd, uint64_t cookie)
 	 * to make sure triggers run correctly.
 	 */
 	session_set_user(session, ADMIN, ADMIN);
-	for (int i = 0; i < SESSION_SEED_SIZE/sizeof(*session->salt); i++)
-		session->salt[i] = rand();
+	random_bytes(session->salt, SESSION_SEED_SIZE);
 	struct mh_i32ptr_node_t node;
 	node.key = session->id;
 	node.val = session;
diff --git a/src/session.h b/src/session.h
index ab0e620ba1311d7bace4338913799f57479056b4..8f9ef818ea624d9aa01d6757476d5396a4ebfc79 100644
--- a/src/session.h
+++ b/src/session.h
@@ -53,7 +53,7 @@ struct session {
 	/** Peer cookie - description of the peer. */
 	uint64_t cookie;
 	/** Authentication salt. */
-	int salt[SESSION_SEED_SIZE/sizeof(int)];
+	char salt[SESSION_SEED_SIZE];
 	/** A look up key to quickly find session user. */
 	uint8_t auth_token;
 	/** User id of the authenticated user. */
diff --git a/src/tarantool.cc b/src/tarantool.cc
index fe1dcb54851b53b4c57b3f6e5456c2b0a1cc1bfd..bc9700996019cc263b3e59c061d4690060439d27 100644
--- a/src/tarantool.cc
+++ b/src/tarantool.cc
@@ -61,6 +61,7 @@
 #include "box/box.h"
 #include "scoped_guard.h"
 #include "random.h"
+#include "tt_uuid.h"
 #include "iobuf.h"
 #include <third_party/gopt/gopt.h>
 #include "cfg.h"
@@ -511,6 +512,7 @@ tarantool_free(void)
 	session_free();
 	fiber_free();
 	memory_free();
+	random_free();
 #ifdef ENABLE_GCOV
 	__gcov_flush();
 #endif
diff --git a/src/trivia/config.h.cmake b/src/trivia/config.h.cmake
index a89e0548185d34ab5749ec2e3b3c8b2e542e17bb..e04b7cb4b66c48c495d5fcf65bd6bf607a186895 100644
--- a/src/trivia/config.h.cmake
+++ b/src/trivia/config.h.cmake
@@ -133,8 +133,7 @@
 #cmakedefine HAVE_OPEN_MEMSTREAM 1
 #cmakedefine HAVE_FMEMOPEN 1
 
-#cmakedefine HAVE_LIBUUID_LINUX 1
-#cmakedefine HAVE_LIBUUID_BSD 1
+#cmakedefine HAVE_UUIDGEN 1
 
 /*
  * predefined /etc directory prefix.
diff --git a/src/tt_uuid.c b/src/tt_uuid.c
index 590e2d81c1c92736854a94883fa5e1b058fca352..d56eea58f096766219986eeddb59a0aaa6a30ceb 100644
--- a/src/tt_uuid.c
+++ b/src/tt_uuid.c
@@ -28,11 +28,54 @@
  */
 #include "tt_uuid.h"
 #include "msgpuck/msgpuck.h"
-#include <stdio.h>
+#include <random.h>
+#include <trivia/config.h>
 
 /* Zeroed by the linker. */
 const struct tt_uuid uuid_nil;
 
+#define CT_ASSERT(e) typedef char __ct_assert_##__LINE__[(e) ? 1 : -1]
+CT_ASSERT(sizeof(struct tt_uuid) == UUID_LEN);
+
+#if defined(HAVE_UUIDGEN)
+#include <sys/uuid.h>
+
+CT_ASSERT(sizeof(struct tt_uuid) == sizeof(struct uuid));
+
+void
+tt_uuid_create(struct tt_uuid *uu)
+{
+	uuidgen((struct uuid *) uu, 1); /* syscall */
+}
+#else
+
+void
+tt_uuid_create(struct tt_uuid *uu)
+{
+	random_bytes((char *) uu, sizeof(*uu));
+
+	uu->clock_seq_hi_and_reserved &= 0x3f;
+	uu->clock_seq_hi_and_reserved |= 0x80; /* variant 1 = RFC4122 */
+	uu->time_hi_and_version &= 0x0FFF;
+	uu->time_hi_and_version |= (4 << 12);  /* version 4 = random */
+}
+#endif
+
+extern inline int
+tt_uuid_from_string(const char *in, struct tt_uuid *uu);
+
+extern inline void
+tt_uuid_to_string(const struct tt_uuid *uu, char *out);
+
+extern inline void
+tt_uuid_bswap(struct tt_uuid *uu);
+
+extern inline bool
+tt_uuid_is_nil(const struct tt_uuid *uu);
+
+extern inline bool
+tt_uuid_is_equal(const struct tt_uuid *lhs, const struct tt_uuid *rhs);
+
 static __thread char buf[UUID_STR_LEN + 1];
 
 char *
diff --git a/src/tt_uuid.h b/src/tt_uuid.h
index 34ece80e3487ad84611ffda0157964bc9215ec67..09f519133863153bdc306471c62ff3d26bab5342 100644
--- a/src/tt_uuid.h
+++ b/src/tt_uuid.h
@@ -28,11 +28,12 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <trivia/config.h>
 #include <string.h>
+#include <stdint.h>
 #include <stdbool.h>
-#include <stdlib.h>
-#include <assert.h>
+#include <string.h>
+#include <stdio.h> /* snprintf */
+#include <lib/bit/bit.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -40,108 +41,102 @@ extern "C" {
 
 enum { UUID_LEN = 16, UUID_STR_LEN = 36 };
 
-#if defined(HAVE_LIBUUID_LINUX)
-
-#include <uuid/uuid.h>
-
-struct tt_uuid {
-	uuid_t id;
-};
-
-static inline void
-tt_uuid_create(struct tt_uuid *uu)
-{
-	uuid_generate(uu->id);
-}
-
-static inline int
-tt_uuid_from_string(const char *in, struct tt_uuid *uu)
-{
-	return uuid_parse((char *) in, uu->id);
-}
-
-static inline void
-tt_uuid_to_string(const struct tt_uuid *uu, char *out)
-{
-	uuid_unparse(uu->id, out);
-}
-
-static inline void
-tt_uuid_bin(const struct tt_uuid *uu, void *out)
-{
-	memcpy(out, uu->id, sizeof(uu->id));
-}
-
-static inline bool
-tt_uuid_is_nil(const struct tt_uuid *uu)
-{
-	return uuid_is_null(uu->id);
-}
-
-static inline bool
-tt_uuid_cmp(const struct tt_uuid *lhs, const struct tt_uuid *rhs)
-{
-	return uuid_compare(lhs->id, rhs->id);
-}
-
-#elif defined(HAVE_LIBUUID_BSD)
-
-#include <uuid.h>
-
+/**
+ * \brief UUID structure struct
+ */
 struct tt_uuid {
-	struct uuid id;
+	uint32_t time_low;
+	uint16_t time_mid;
+	uint16_t time_hi_and_version;
+	uint8_t clock_seq_hi_and_reserved;
+	uint8_t clock_seq_low;
+	uint8_t node[6];
 };
 
-static inline int
-tt_uuid_create(struct tt_uuid *uu)
-{
-	uint32_t status;
-	uuid_create(&uu->id, &status);
-	return status == uuid_s_ok;
-}
-
-static inline int
+/**
+ * \brief Generate new UUID
+ * \param uu[out] UUID
+ */
+void
+tt_uuid_create(struct tt_uuid *uu);
+
+/**
+ * \brief Parse UUID from string.
+ * \param in string
+ * \param uu[out] UUID
+ * \return
+ */
+inline int
 tt_uuid_from_string(const char *in, struct tt_uuid *uu)
 {
-	uint32_t status;
-	uuid_from_string(in, &uu->id, &status);
-	return status == uuid_s_ok;
+	if (strlen(in) != UUID_STR_LEN ||
+	    sscanf(in, "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+		   &uu->time_low, &uu->time_mid, &uu->time_hi_and_version,
+		   &uu->clock_seq_hi_and_reserved, &uu->clock_seq_low,
+		   &uu->node[0], &uu->node[1], &uu->node[2], &uu->node[3],
+		   &uu->node[4], &uu->node[5]) != 11)
+		return 1;
+
+	/* Check variant (NCS, RFC4122, MSFT) */
+	uint8_t n = uu->clock_seq_hi_and_reserved;
+	if ((n & 0x80) != 0x00 && (n & 0xc0) != 0x80 &&	(n & 0xe0) != 0xc0)
+		return 1;
+	return 0;
 }
 
-static inline void
+/**
+ * \brief Format UUID to RFC 4122 string.
+ * \param uu uuid
+ * \param[out] out buffer, must be at least UUID_STR_LEN + 1 length
+ */
+inline void
 tt_uuid_to_string(const struct tt_uuid *uu, char *out)
 {
-	uint32_t status;
-	char *buf = NULL;
-	uuid_to_string(&uu->id, &buf, &status);
-	assert(status == uuid_s_ok);
-	strncpy(out, buf, UUID_STR_LEN);
-	out[UUID_STR_LEN] = '\0';
-	free(buf);
+	sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+		uu->time_low, uu->time_mid, uu->time_hi_and_version,
+		uu->clock_seq_hi_and_reserved, uu->clock_seq_low, uu->node[0],
+		uu->node[1], uu->node[2], uu->node[3], uu->node[4], uu->node[5]);
 }
 
-static inline bool
-tt_uuid_cmp(const struct tt_uuid *lhs, const struct tt_uuid *rhs)
+/**
+ * \brief Return byte order swapped UUID (LE -> BE and vice versa)
+ * \param uu
+ */
+inline void
+tt_uuid_bswap(struct tt_uuid *uu)
 {
-	uint32_t status;
-	return uuid_compare(&lhs->id, &rhs->id, &status);
+	uu->time_low = bswap_u32(uu->time_low);
+	uu->time_mid = bswap_u16(uu->time_mid);
+	uu->time_hi_and_version = bswap_u16(uu->time_hi_and_version);
 }
 
-static inline bool
+/**
+ * \brief Test that uuid is nil
+ * \param uu UUID
+ * \retval true if all members of \a uu 0
+ * \retval false otherwise
+ */
+inline bool
 tt_uuid_is_nil(const struct tt_uuid *uu)
 {
-	uint32_t status;
-	return uuid_is_nil(&uu->id, &status);
+	const uint64_t *p = (const uint64_t *) uu;
+	return !p[0] && !p[1];
 }
 
-static inline void
-tt_uuid_bin(const struct tt_uuid *uu, void *out)
+/**
+ * \brief Test that \a lhs equal \a rhs
+ * \param lhs UUID
+ * \param rhs UUID
+ * \retval true if \a lhs equal \a rhs
+ * \retval false otherwise
+ */
+inline bool
+tt_uuid_is_equal(const struct tt_uuid *lhs, const struct tt_uuid *rhs)
 {
-	uuid_enc_le(out, &uu->id);
+	const uint64_t *lp = (const uint64_t *) lhs;
+	const uint64_t *rp = (const uint64_t *) rhs;
+	return lp[0] == rp[0] && lp[1] == rp[1];
 }
-#else
-#error Unsupported libuuid
-#endif /* HAVE_LIBUUID_XXX */
 
 extern const struct tt_uuid uuid_nil;
 
diff --git a/test/box/uuid.result b/test/box/uuid.result
index 7e12ebc149d177f59474796aa97619841801f63a..eb5fba13da12238466bf9c828d3d4984bb90b9ea 100644
--- a/test/box/uuid.result
+++ b/test/box/uuid.result
@@ -2,18 +2,248 @@
 uuid = require('uuid')
 ---
 ...
-string.len(uuid.bin())
+--
+-- RFC4122 compliance
+--
+uu = uuid.new()
+---
+...
+-- new()always generates RFC4122 variant
+bit.band(uu.clock_seq_hi_and_reserved, 0xc0) == 0x80
+---
+- true
+...
+vsn = bit.rshift(uu.time_hi_and_version, 12)
+---
+...
+-- new() generates time-based or random-based version
+vsn == 1 or vsn == 4
+---
+- true
+...
+--
+-- to/from string
+--
+uu = uuid()
+---
+...
+#uu:str()
+---
+- 36
+...
+string.match(uu:str(), '^[a-f0-9%-]+$') ~= nil
+---
+- true
+...
+uu == uuid.fromstr(uu:str())
+---
+- true
+...
+uu = uuid.fromstr('ba90d815-14e0-431d-80c0-ce587885bb78')
+---
+...
+uu:str()
+---
+- ba90d815-14e0-431d-80c0-ce587885bb78
+...
+tostring(uu)
+---
+- ba90d815-14e0-431d-80c0-ce587885bb78
+...
+tostring(uu) == uu:str()
+---
+- true
+...
+uu.time_low;
+---
+- 3130054677
+...
+uu.time_mid;
+---
+- 5344
+...
+uu.time_hi_and_version;
+---
+- 17181
+...
+uu.clock_seq_hi_and_reserved;
+---
+- 128
+...
+uu.clock_seq_low;
+---
+- 192
+...
+uu.node[0]
+---
+- 206
+...
+uu.node[1]
+---
+- 88
+...
+uu.node[2]
+---
+- 120
+...
+uu.node[3]
+---
+- 133
+...
+uu.node[4]
+---
+- 187
+...
+uu.node[5]
+---
+- 120
+...
+-- aliases
+#uuid.str()
+---
+- 36
+...
+-- invalid values
+uuid.fromstr(nil)
+---
+- error: 'builtin/uuid.lua:44: fromstr(str)'
+...
+uuid.fromstr('')
+---
+- null
+...
+uuid.fromstr('blablabla')
+---
+- null
+...
+uuid.fromstr(string.rep(' ', 36))
+---
+- null
+...
+uuid.fromstr('ba90d81514e0431d80c0ce587885bb78')
+---
+- null
+...
+uuid.fromstr('ba90d815-14e0-431d-80c0')
+---
+- null
+...
+uuid.fromstr('ba90d815-14e0-431d-80c0-tt587885bb7')
+---
+- null
+...
+--
+-- to/from binary
+--
+uu = uuid()
+---
+...
+#uu:bin()
 ---
 - 16
 ...
-string.len(uuid.hex())
+#uu:bin('h')
 ---
-- 32
+- 16
+...
+#uu:bin('l')
+---
+- 16
+...
+#uu:bin('n')
+---
+- 16
+...
+#uu:bin('b')
+---
+- 16
+...
+uu:bin() == uu:bin('h')
+---
+- true
 ...
-string.match(uuid.hex(), '^[a-f0-9]+$') ~= nil
+uu:bin('n') ~= uu:bin('h')
 ---
 - true
 ...
+uu:bin('b') ~= uu:bin('l')
+---
+- true
+...
+uu == uuid.frombin(uu:bin())
+---
+- true
+...
+uu == uuid.frombin(uu:bin('b'), 'b')
+---
+- true
+...
+uu == uuid.frombin(uu:bin('l'), 'l')
+---
+- true
+...
+uu = uuid.fromstr('adf9d02e-0756-11e4-b5cf-525400123456')
+---
+...
+uu:bin('l')
+---
+- !!binary LtD5rVYH5BG1z1JUABI0Vg==
+...
+uu:bin('b')
+---
+- !!binary rfnQLgdWEeS1z1JUABI0Vg==
+...
+-- aliases
+#uuid.bin()
+---
+- 16
+...
+#uuid.bin('l')
+---
+- 16
+...
+--
+-- eq and nil
+--
+uu = uuid.new()
+---
+...
+uuid.NULL
+---
+- 00000000-0000-0000-0000-000000000000
+...
+uuid.NULL:isnil()
+---
+- true
+...
+uuid.NULL ~= uu
+---
+- true
+...
+uu:isnil()
+---
+- false
+...
+uu ==  uu
+---
+- true
+...
+uu == uu
+---
+- true
+...
+uu == nil
+---
+- false
+...
+uu == 12345
+---
+- false
+...
+uu == "blablabla"
+---
+- false
+...
 uuid = nil
 ---
 ...
diff --git a/test/box/uuid.test.lua b/test/box/uuid.test.lua
index 244e15c11dff566f780b98d07589ae305fe28372..c1c0a8bd9552270114b0687ea19796e68e2534a9 100644
--- a/test/box/uuid.test.lua
+++ b/test/box/uuid.test.lua
@@ -1,6 +1,88 @@
 -- box.uuid
 uuid = require('uuid')
-string.len(uuid.bin())
-string.len(uuid.hex())
-string.match(uuid.hex(), '^[a-f0-9]+$') ~= nil
+
+--
+-- RFC4122 compliance
+--
+uu = uuid.new()
+-- new()always generates RFC4122 variant
+bit.band(uu.clock_seq_hi_and_reserved, 0xc0) == 0x80
+vsn = bit.rshift(uu.time_hi_and_version, 12)
+-- new() generates time-based or random-based version
+vsn == 1 or vsn == 4
+
+--
+-- to/from string
+--
+uu = uuid()
+#uu:str()
+string.match(uu:str(), '^[a-f0-9%-]+$') ~= nil
+uu == uuid.fromstr(uu:str())
+uu = uuid.fromstr('ba90d815-14e0-431d-80c0-ce587885bb78')
+uu:str()
+tostring(uu)
+tostring(uu) == uu:str()
+uu.time_low;
+uu.time_mid;
+uu.time_hi_and_version;
+uu.clock_seq_hi_and_reserved;
+uu.clock_seq_low;
+uu.node[0]
+uu.node[1]
+uu.node[2]
+uu.node[3]
+uu.node[4]
+uu.node[5]
+
+-- aliases
+#uuid.str()
+
+-- invalid values
+uuid.fromstr(nil)
+uuid.fromstr('')
+uuid.fromstr('blablabla')
+uuid.fromstr(string.rep(' ', 36))
+uuid.fromstr('ba90d81514e0431d80c0ce587885bb78')
+uuid.fromstr('ba90d815-14e0-431d-80c0')
+uuid.fromstr('ba90d815-14e0-431d-80c0-tt587885bb7')
+
+--
+-- to/from binary
+--
+uu = uuid()
+#uu:bin()
+#uu:bin('h')
+#uu:bin('l')
+#uu:bin('n')
+#uu:bin('b')
+uu:bin() == uu:bin('h')
+uu:bin('n') ~= uu:bin('h')
+uu:bin('b') ~= uu:bin('l')
+uu == uuid.frombin(uu:bin())
+uu == uuid.frombin(uu:bin('b'), 'b')
+uu == uuid.frombin(uu:bin('l'), 'l')
+
+uu = uuid.fromstr('adf9d02e-0756-11e4-b5cf-525400123456')
+uu:bin('l')
+uu:bin('b')
+
+-- aliases
+#uuid.bin()
+#uuid.bin('l')
+
+--
+-- eq and nil
+--
+
+uu = uuid.new()
+uuid.NULL
+uuid.NULL:isnil()
+uuid.NULL ~= uu
+uu:isnil()
+uu ==  uu
+uu == uu
+uu == nil
+uu == 12345
+uu == "blablabla"
+
 uuid = nil