diff --git a/client/tarantool/tc_buf.c b/client/tarantool/tc_buf.c
index b4556bb796078d1b86f5b54a84b2146268e22c87..4826ed1361294867c03afb24155875d829d138a5 100644
--- a/client/tarantool/tc_buf.c
+++ b/client/tarantool/tc_buf.c
@@ -37,9 +37,10 @@
 /* Strip trailing ws from (char*) */
 size_t strip_end_ws(char *str) {
 	size_t last = 0;
-	for (size_t i = 0; str[i] != 0; ++i)
+	for (size_t i = 0; str[i] != 0; ++i) {
 		if (!isspace(str[i]))
 			last = i + 1;
+	}
 	str[last] = '\0';
 	return last;
 }
@@ -49,16 +50,18 @@ int tc_buf(struct tc_buf *buf) {
 	buf->size = TC_BUF_INIT_SIZE;
 	buf->used = 0;
 	buf->data = (char *)malloc(buf->size);
-	if (buf->data == NULL)
+	if (buf->data == NULL) {
 		return -1;
+	}
 	return 0;
 }
 
 /* Append len bytes of memory from str pointed memory */
 int tc_buf_append(struct tc_buf *buf, void *str, size_t len) {
 	if (buf->size - buf->used < len) {
-		if (buf->size < len)
+		if (buf->size < len) {
 			buf->size = len;
+		}
 		buf->size *= TC_BUF_MULTIPLIER;
 		char *nd = (char *)realloc(buf->data, buf->size);
 		if (nd == NULL)
@@ -112,6 +115,26 @@ int tc_buf_str_append(struct tc_buf *buf, char *str, size_t len) {
 	return 0;
 }
 
+/* Remove last num symbols from STR */
+size_t tc_buf_str_delete(struct tc_buf *buf, size_t len) {
+	size_t ret = tc_buf_delete(buf, len + 1); /* Remove '\0' + len */
+	if (tc_buf_append(buf, (void *)"\0", 1))
+		return 0;
+	return ret;
+}
+
+/*
+ * Make admin command from multiline command
+ * and delete delimiter (last num bytes)
+ */
+void tc_buf_cmdfy(struct tc_buf *buf, size_t num) {
+	tc_buf_str_delete(buf, num);
+	for (int i = 0; i < buf->used; ++i) {
+		if (buf->data[i] == '\n')
+			buf->data[i] = ' ';
+	}
+}
+
 /* Remove trailing ws from STR */
 int tc_buf_str_stripws(struct tc_buf *buf) {
 	if (buf->data) {
diff --git a/client/tarantool/tc_buf.h b/client/tarantool/tc_buf.h
index 52383666e7a7adf1cd869c1e96ff3a4e197d781d..3e528c20d7742a424aa9a4c417f81a5d8f7ddd39 100644
--- a/client/tarantool/tc_buf.h
+++ b/client/tarantool/tc_buf.h
@@ -40,12 +40,15 @@ struct tc_buf {
 int tc_buf(struct tc_buf *buf);
 void *tc_buf_realloc(void *data, size_t size);
 int tc_buf_append(struct tc_buf *buf, void *str, size_t len);
-size_t tc_buf_delete(struct tc_buf *buf, size_t len);
+size_t tc_buf_delete(struct tc_buf *buf, size_t num);
 int tc_buf_isempty(struct tc_buf *buf);
 void tc_buf_clear(struct tc_buf *buf);
 void tc_buf_free(struct tc_buf *buf);
 
 int tc_buf_str(struct tc_buf *buf);
 int tc_buf_str_append(struct tc_buf *buf, char *str, size_t len);
+size_t tc_buf_str_delete(struct tc_buf *buf, size_t num);
 int tc_buf_str_stripws(struct tc_buf *buf);
 int tc_buf_str_isempty(struct tc_buf *buf);
+
+void tc_buf_cmdfy(struct tc_buf *buf, size_t num);
diff --git a/client/tarantool/tc_cli.c b/client/tarantool/tc_cli.c
index 90894ee554fe2f588923cd59a45ce024f9101f5e..53fda89668654c5590b5b94f9cf9352dcc7f1d25 100644
--- a/client/tarantool/tc_cli.c
+++ b/client/tarantool/tc_cli.c
@@ -124,13 +124,13 @@ tc_cmd_usage(void)
 {
 	char usage[] =
 		"---\n"
-		"- console client commands\n"
-		"- - help\n"
-		"  - tee 'path'\n"
-		"  - notee\n"
-		"  - loadfile 'path'\n"
-		"  - setopt key=val\n"
-		"  - (possible pairs: delim[iter]=\'string\')\n"
+		"console client commands:\n"
+		" - help\n"
+		" - tee 'path'\n"
+		" - notee\n"
+		" - loadfile 'path'\n"
+		" - setopt key val\n"
+		" - (possible pairs: delimiter 'string')\n"
 		"...\n";
 	tc_printf("%s", usage);
 }
@@ -224,6 +224,17 @@ tc_cmd_loadfile(char *path, int *reconnect)
 	return rc;
 }
 
+static void replace_newline(char *cmd) {
+	int len = strlen(cmd);
+	int offset = 0;
+	for (int i = 0; i < len - 1; ++i)
+		if (cmd[i] == '\\' && cmd[i + 1] == 'n')
+			cmd[i++ - offset++] = '\n';
+		else if (offset != 0)
+			cmd[i - offset] = cmd[i];
+	cmd[len - offset] = '\0';
+}
+
 static enum tc_cli_cmd_ret
 tc_cmd_try(char *cmd, size_t size, int *reconnect)
 {
@@ -262,8 +273,10 @@ tc_cmd_try(char *cmd, size_t size, int *reconnect)
 	case TC_SETOPT:
 		switch (tnt_lex(&lex, &tk)) {
 		case TC_SETOPT_DELIM:
-			if (tnt_lex(&lex, &tk) == '=' &&
-			    tnt_lex(&lex, &tk) == TNT_TK_STRING) {
+			if (tnt_lex(&lex, &tk) != '=') {
+				tnt_lex_push(&lex, tk);
+			}
+			if (tnt_lex(&lex, &tk) == TNT_TK_STRING) {
 				if (!TNT_TK_S(tk)->size) {
 					tc.opt.delim = "";
 					tc.opt.delim_len = 0;
@@ -276,11 +289,12 @@ tc_cmd_try(char *cmd, size_t size, int *reconnect)
 				strncpy(temp,
 					(const char *)TNT_TK_S(tk)->data,
 					TNT_TK_S(tk)->size + 1);
+				replace_newline(temp);
 				tc.opt.delim = temp;
 				tc.opt.delim_len = strlen(tc.opt.delim);
 			} else {
 				tc_printf("---\n");
-				tc_printf(" - Expected: setopt delim[iter]='string'\n");
+				tc_printf(" - Expected `setopt delimiter 'string'`\n");
 				tc_printf("---\n");
 			}
 			break;
@@ -380,9 +394,9 @@ static char* tc_cli_readline_pipe() {
 				ungetc(c_t, stdin);
 			wctomb(str + pos++, 0);
 			break;
-		}
-		else
+		} else {
 			pos += wctomb(str + pos, c);
+		}
 	}
 	if (pos == 1 && c == WEOF) {
 		free(str);
@@ -393,7 +407,6 @@ static char* tc_cli_readline_pipe() {
 
 static int check_delim(char* str, size_t len, size_t sep_len) {
 	const char *sep = tc.opt.delim;
-	len = strip_end_ws(str);
 	if (sep_len == 0)
 		return 1;
 	if (len < sep_len)
@@ -402,8 +415,6 @@ static int check_delim(char* str, size_t len, size_t sep_len) {
 	for (i = len; sep_len > 0; --sep_len, --i)
 		if (str[i - 1] != sep[sep_len - 1])
 			return 0;
-	str[i] = '\0';
-	len = strip_end_ws(str);
 	return 1;
 }
 
@@ -433,44 +444,44 @@ int tc_cli(void)
 		if (isatty(STDIN_FILENO)) {
 			snprintf(prompt_delim, sizeof(prompt_delim),
 				 "%*s> ", prompt_len, "-");
-			part_cmd = readline(!tc_buf_str_isempty(&cmd) ? prompt_delim
-							   : prompt);
+			part_cmd = readline(! tc_buf_str_isempty(&cmd)
+					    ? prompt_delim
+					    : prompt);
 		} else {
 			clearerr(stdin);
 			part_cmd = tc_cli_readline_pipe();
 		}
 		if (!part_cmd)
 			break;
-		size_t part_cmd_len = strlen(part_cmd);
-		int delim_exists = check_delim(part_cmd,
-					       part_cmd_len,
-					       tc.opt.delim_len);
 		if (tc_buf_str_append(&cmd, part_cmd, strlen(part_cmd)))
 			tc_error(TC_REALLOCATION_ERROR,
 				 cmd.size);
+		int delim_exists = check_delim( cmd.data,
+						cmd.used - 1,
+						tc.opt.delim_len);
+		if (tc_buf_str_append(&cmd, "\n", 1)) /* Append '\n' to the STR */
+			tc_error(TC_REALLOCATION_ERROR,
+				 cmd.size);
 		free(part_cmd);
-		if (!delim_exists && !feof(stdin)) {
-			if (tc_buf_str_append(&cmd, " ", 1))
-				tc_error(TC_REALLOCATION_ERROR,
-					 cmd.size);
+		if (!delim_exists && !feof(stdin)) /* If still without delimiter and not EOF */
 			continue;
-		}
-		tc_buf_str_stripws(&cmd);
+		tc_buf_str_delete(&cmd, 1); /* Delete last appended '\n' */
+		if (isatty(STDIN_FILENO)) /* Enable history on readline use only */
+			add_history(cmd.data);
+		tc_buf_cmdfy(&cmd, tc.opt.delim_len); /* Create admin cmd from STR */
 		if (delim_exists && tc_buf_str_isempty(&cmd))
-			goto next;
+			goto next; /* If empty - don't send to server, it crashes */
 		tc_print_cmd2tee(cmd.used != 1 ? prompt_delim : prompt,
 				 cmd.data, cmd.used - 1);
 		enum tc_cli_cmd_ret ret = tc_cli_cmd(cmd.data,
 						     cmd.used - 1);
-		if (isatty(STDIN_FILENO))
-			add_history(cmd.data);
 next:
 		tc_buf_clear(&cmd);
 		if (ret == TC_CLI_EXIT || feof(stdin)) {
 			tc_buf_free(&cmd);
 			break;
 		}
-}
+	}
 
 	/* updating history file */
 	write_history(history);