diff --git a/src/box/lua/sql.lua b/src/box/lua/sql.lua
index 0a895892728aac2d00ea399f9aa042e2b3c83626..c9a7001363616e0d586845985276785a5221bf97 100644
--- a/src/box/lua/sql.lua
+++ b/src/box/lua/sql.lua
@@ -174,6 +174,40 @@ box.net.sql = {
         -- quote identifier
         quote_ident = function(self, variable)
             return self.raw:quote_ident(variable)
+        end,
+
+
+        -- begin transaction
+        begin_work = function(self)
+            return self:perform('BEGIN')
+        end,
+
+        -- commit transaction
+        commit  = function(self)
+            return self:perform('COMMIT')
+        end,
+
+        -- rollback transaction
+        rollback = function(self)
+            return self:perform('ROLLBACK')
+        end,
+
+        -- transaction
+        txn = function(self, proc)
+            local raise = self.raise
+            self.raise = true
+            self:begin_work()
+            local res = { pcall(proc, self) }
+
+            self.raise = raise
+            
+            if res[1] then
+                self:commit()
+                return true
+            end
+
+            self:rollback()
+            return false, res[2]
         end
     }
 
diff --git a/src/lua/pg.cc b/src/lua/pg.cc
index c155fe85240b38dd001cdd7eafed24b14667854d..0022f6dd5312dd976c7aa460f57bd690b4bd2656 100644
--- a/src/lua/pg.cc
+++ b/src/lua/pg.cc
@@ -267,6 +267,15 @@ lua_pg_gc(struct lua_State *L)
 	return 0;
 }
 
+/**
+ * prints warnings from Postgresql into tarantool log
+ */
+static void
+pg_notice(void *arg, const char *message)
+{
+	say_info("Postgresql: %s", message);
+	(void)arg;
+}
 
 /**
  * do connect to postgresql (is run in the other thread)
@@ -277,6 +286,8 @@ pg_connect(va_list ap)
 	const char *constr = va_arg(ap, typeof(constr));
 	PGconn **conn = va_arg(ap, typeof(conn));
 	*conn = PQconnectdb(constr);
+	if (*conn)
+		PQsetNoticeProcessor(*conn, pg_notice, NULL);
 	return 0;
 }
 
diff --git a/test/box/net_sql.mysql.result b/test/box/net_sql.mysql.result
index 5fbb88b143bb8d77553cff619235b02fa07eceef..b0d0697b79744f6575defe3105c63e8c93346b6f 100644
--- a/test/box/net_sql.mysql.result
+++ b/test/box/net_sql.mysql.result
@@ -63,3 +63,19 @@ lua c:quote('test "abc" test')
 ---
  - test \"abc\" test
 ...
+lua c:begin_work()
+---
+ - 0
+...
+lua c:rollback()
+---
+ - 0
+...
+lua c:begin_work()
+---
+ - 0
+...
+lua c:commit()
+---
+ - 0
+...
diff --git a/test/box/net_sql.mysql.test b/test/box/net_sql.mysql.test
index f44c6c4599e7049ca6562eed24006aebfbd44156..d69d064869cae1a0cc74f63f466f231059787e4c 100644
--- a/test/box/net_sql.mysql.test
+++ b/test/box/net_sql.mysql.test
@@ -20,3 +20,8 @@ exec admin "lua dump({c:execute('SELECT 1 AS one UNION ALL SELECT 2')})"
 exec admin "lua dump({c:execute('SELECT 1 AS one UNION ALL SELECT 2; SELECT ? AS two', 'abc')})"
 
 exec admin "lua c:quote('test \"abc\" test')"
+
+exec admin "lua c:begin_work()"
+exec admin "lua c:rollback()"
+exec admin "lua c:begin_work()"
+exec admin "lua c:commit()"
diff --git a/test/box/net_sql.pg.result b/test/box/net_sql.pg.result
index b7b3e0d488e08f75cbf5f26dfb81f1f0648ed169..c332d724237d20912431c0f4860f7601a84053e3 100644
--- a/test/box/net_sql.pg.result
+++ b/test/box/net_sql.pg.result
@@ -93,3 +93,23 @@ lua c:quote('abc"cde"def')
 ---
  - 'abc"cde"def'
 ...
+lua c:begin_work()
+---
+ - 0
+...
+lua c:rollback()
+---
+ - 0
+...
+lua c:begin_work()
+---
+ - 0
+...
+lua c:commit()
+---
+ - 0
+...
+lua c:txn(function(dbi) dbi:single('SELECT 1') end)
+---
+ - true
+...
diff --git a/test/box/net_sql.pg.test b/test/box/net_sql.pg.test
index 00311e85214843d9b2a3447da3857a31a2a4178d..bab88bb34bfb0bd0585abad6fb66c9617ba87998 100644
--- a/test/box/net_sql.pg.test
+++ b/test/box/net_sql.pg.test
@@ -30,3 +30,11 @@ exec admin "lua c = box.net.sql.connect('abcd')"
 
 
 exec admin "lua c:quote('abc\"cde\"def')"
+
+
+exec admin "lua c:begin_work()"
+exec admin "lua c:rollback()"
+exec admin "lua c:begin_work()"
+exec admin "lua c:commit()"
+
+exec admin "lua c:txn(function(dbi) dbi:single('SELECT 1') end)"