diff --git a/pgproto/src/postgres/port.c b/pgproto/src/postgres/port.c
index 5777ba93f3aea36502d093ba41324e713ff59243..03a8ac57c7ffd2af815b3b8107654cd56f9ed7a7 100644
--- a/pgproto/src/postgres/port.c
+++ b/pgproto/src/postgres/port.c
@@ -77,6 +77,25 @@ pg_port_close(struct pg_port *port)
 	free(port->user);
 }
 
+char *
+pg_read_cstr(struct pg_port *port, size_t *len)
+{
+	uint32_t packet_len;
+	if (pg_read_uint32(port, &packet_len) < 0)
+		return NULL;
+
+	if (packet_len < sizeof(uint32_t) + 1)
+		return NULL;
+
+	size_t cstr_len = packet_len - sizeof(uint32_t);
+	char *query = pg_read_bytes(port, cstr_len);
+	if (query == NULL || query[cstr_len - 1] != '\0')
+		return NULL;
+
+	*len = cstr_len - 1;
+	return query;
+}
+
 void *
 pg_read_bytes(struct pg_port *port, size_t size)
 {
diff --git a/pgproto/src/postgres/port.h b/pgproto/src/postgres/port.h
index 965ae0cef859cde7acf2dc92286f988108d5c296..a37f2565e96fbc97d5a0d07355fce926411bd6ec 100644
--- a/pgproto/src/postgres/port.h
+++ b/pgproto/src/postgres/port.h
@@ -77,6 +77,17 @@ pg_port_create(struct pg_port *port, struct iostream *io);
 void
 pg_port_close(struct pg_port *port);
 
+/**
+ * Read a null-terminated string to the port buffer, set size to its length
+ * excluding the terminator and return a pointer to the data read.
+ *
+ * @retval not-NULL on success.
+ * @retval NULL on EOF or error,
+ *         check pg_port::state to understand what happened.
+ */
+char *
+pg_read_cstr(struct pg_port *port, size_t *size);
+
 /**
  * Read size bytes to the port buffer and return a pointer to the data read.
  *
diff --git a/pgproto/src/postgres/postgres.c b/pgproto/src/postgres/postgres.c
index 49da853f29ce09ce286b173f2f640f4b4db8dd1f..1aeca7db5f54b1c82f36acc7c109a4b0109bc795 100644
--- a/pgproto/src/postgres/postgres.c
+++ b/pgproto/src/postgres/postgres.c
@@ -1,8 +1,8 @@
 #include <module.h>
 #include <msgpuck.h>
 #include <inttypes.h>
-#include <strings.h> /* for strncasecmp */
-#include <ctype.h> /* for isspace */
+#include <strings.h>
+#include <ctype.h>
 
 #include "postgres.h"
 #include "report.h"
@@ -12,7 +12,6 @@
 #include "attributes.h"
 #include "tarantool/trivia/util.h"
 
-
 /**
  * Format of ReadyForQuery message.
  * ReadyForQuery informs the frontend that it can safely send a new command.
@@ -56,26 +55,6 @@ struct query_message {
 	const char *query;
 };
 
-/** Read query string consistin in QueryMessage  */
-static const char *
-read_query_string(struct pg_port *port, size_t *query_len)
-{
-	struct query_message message;
-	if (pg_read_uint32(port, &message.len) < 0)
-		goto error;
-
-	*query_len = message.len - sizeof(message.len);
-	message.query = pg_read_bytes(port, *query_len);
-	if (message.query == NULL)
-		goto error;
-
-	return message.query;
-error:
-	pg_error(NULL, ERRCODE_INTERNAL_ERROR,
-		 "failed to read a query message");
-	return NULL;
-}
-
 #define COMPARE_AND_RETURN_IF_EQUALS(query, tag)	\
 	if (strncasecmp(query, tag, strlen(tag)) == 0)	\
 		return tag
@@ -360,9 +339,12 @@ static int
 process_simple_query_impl(struct pg_port *port)
 {
 	size_t query_len;
-	const char *query = read_query_string(port, &query_len);
-	if (query == NULL)
+	const char *query = pg_read_cstr(port, &query_len);
+	if (query == NULL) {
+		pg_error(port, ERRCODE_INTERNAL_ERROR,
+			 "failed to read a query message");
 		return -1;
+	}
 
 	pg_debug("processing query \'%s\'", query);
 	const char *response = dispatch_query_wrapped(query, query_len);
diff --git a/pgproto/test/CMakeLists.txt b/pgproto/test/CMakeLists.txt
index 20bf9083519c38bd8f5f9eaa8b7c5c5cfcb4d17d..c5932d45584cb5744bddf405e4581666770fe93f 100644
--- a/pgproto/test/CMakeLists.txt
+++ b/pgproto/test/CMakeLists.txt
@@ -1,9 +1,11 @@
 get_all_targets(SOURCE_TARGETS ${PROJECT_SOURCE_DIR}/src)
 
+set(LUA_CPATH "${PROJECT_BINARY_DIR}/src/server/?.so")
+
 add_custom_target(test
     DEPENDS ${SOURCE_TARGETS}
     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
     COMMAND ${CMAKE_COMMAND} -E env
     "PICODATA_EXECUTABLE=${PICODATA_EXECUTABLE}"
-    "LUA_CPATH=${PROJECT_BINARY_DIR}/src/server/?.so"
+    "LUA_CPATH=${LUA_CPATH}"
     pytest)
diff --git a/pgproto/test/simple_query_test.py b/pgproto/test/simple_query_test.py
index 110aada8d2717d3dacb7bffd8e79677907db3853..6638208a7a43bf01f2e1e24d21df757bc258d101 100644
--- a/pgproto/test/simple_query_test.py
+++ b/pgproto/test/simple_query_test.py
@@ -7,25 +7,20 @@ import time
 def start_pg_server(instance, host, service):
     start_pg_server_lua_code = f"""
         package.cpath="{os.environ['LUA_CPATH']}"
-        net_box = require('net.box')
-        box.schema.func.create('tcpserver.server_start', {{language = 'C'}})
+
+        box.schema.func.create('tcpserver.server_start', {{ language = 'C' }})
         box.schema.user.grant('guest', 'execute', 'function', 'tcpserver.server_start')
 
-        box.cfg{{listen=3301}}
-        caller = net_box:new(3301)
-        caller:call('tcpserver.server_start', {{ '{host}', '{service}' }})
+        box.func['tcpserver.server_start']:call({{ '{host}', '{service}' }})
     """
     instance.eval(start_pg_server_lua_code)
 
 def stop_pg_server(instance):
     stop_pg_server_lua_code = f"""
-        local net_box = require('net.box')
         box.schema.func.create('tcpserver.server_stop', {{language = 'C'}})
         box.schema.user.grant('guest', 'execute', 'function', 'tcpserver.server_stop')
 
-        box.cfg{{listen=3301}}
-        local caller = net_box:new(3301)
-        caller:call('tcpserver.server_stop')
+        box.func['tcpserver.server_stop']:call()
 
         box.schema.func.drop('tcpserver.server_start')
         box.schema.func.drop('tcpserver.server_stop')
@@ -69,11 +64,11 @@ def test_simple_flow_session(cluster: Cluster):
     i1 = cluster.instances[0]
 
     host = '127.0.0.1'
-    service = '35776'
+    service = '5432'
     start_pg_server(i1, host, service)
 
     user = 'admin'
-    password = '`fANPIOUWEh79p12hdunqwADI`'
+    password = 'password'
     i1.eval("box.cfg{auth_type='md5', log_level=7}")
     i1.eval(f"box.schema.user.passwd('{user}', '{password}')")