diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index fcab5c0d51..8cffc18165 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2799,6 +2799,32 @@ lo_import 152801
           </listitem>
           </varlistentry>
 
+          <varlistentry>
+          <term><literal>xheader_width</literal></term>
+          <listitem>
+          <para>
+          Sets expanded header width to one of <literal>full</literal>,
+          <literal>column</literal>,
+          <literal>page</literal>,
+          or <replaceable class="parameter">integer value</replaceable>.
+          </para>
+
+          <para><literal>full</literal> is the default option - expanded header
+          is not truncated.
+          </para>
+
+          <para><literal>column</literal>: don't print header line past the first
+          column.
+          </para>
+
+          <para><literal>page</literal>: fit header line to terminal width.
+          </para>
+
+          <para><replaceable class="parameter">integer value</replaceable>: specify exact width of header line.
+          </para>
+          </listitem>
+          </varlistentry>
+
           <varlistentry>
           <term><literal>fieldsep</literal></term>
           <listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 49d4c0e3ce..440b732d3c 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -4310,6 +4310,28 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			popt->topt.expanded = !popt->topt.expanded;
 	}
 
+	/* header line width in expanded mode */
+	else if (strcmp(param, "xheader_width") == 0)
+	{
+		if (value && pg_strcasecmp(value, "full") == 0)
+			popt->topt.expanded_header_width_type = PRINT_XHEADER_FULL;
+		else if (value && pg_strcasecmp(value, "column") == 0)
+			popt->topt.expanded_header_width_type = PRINT_XHEADER_COLUMN;
+		else if (value && pg_strcasecmp(value, "page") == 0)
+			popt->topt.expanded_header_width_type = PRINT_XHEADER_PAGE;
+		else if (value) {
+			popt->topt.expanded_header_width_type = PRINT_XHEADER_EXACT_WIDTH;
+			popt->topt.expanded_header_exact_width = atoi(value);
+			if (popt->topt.expanded_header_exact_width == 0) {
+				pg_log_error("\\pset: allowed xheader_width values are full (default), column, page, or an number specifying exact width.");
+				return false;
+			}
+		} else {
+			/* reset to default if value is empty */
+			popt->topt.expanded_header_width_type = PRINT_XHEADER_FULL;
+		}
+	}
+
 	/* field separator for CSV format */
 	else if (strcmp(param, "csv_fieldsep") == 0)
 	{
@@ -4502,6 +4524,19 @@ printPsetInfo(const char *param, printQueryOpt *popt)
 			printf(_("Expanded display is off.\n"));
 	}
 
+	/* show xheader width type */
+	else if (strcmp(param, "xheader_width") == 0)
+	{
+		if (popt->topt.expanded_header_width_type == PRINT_XHEADER_FULL)
+			printf(_("Expanded header width is 'full'.\n"));
+		else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_COLUMN)
+			printf(_("Expanded header width is 'column'.\n"));
+		else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_PAGE)
+			printf(_("Expanded header width is 'page'.\n"));
+		else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
+			printf(_("Expanded header width is %d.\n"), popt->topt.expanded_header_exact_width);
+	}
+
 	/* show field separator for CSV format */
 	else if (strcmp(param, "csv_fieldsep") == 0)
 	{
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 064892bade..22c977d47d 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -4115,13 +4115,16 @@ psql_completion(const char *text, int start, int end)
 						 "tableattr", "title", "tuples_only",
 						 "unicode_border_linestyle",
 						 "unicode_column_linestyle",
-						 "unicode_header_linestyle");
+						 "unicode_header_linestyle",
+						 "xheader_width");
 	else if (TailMatchesCS("\\pset", MatchAny))
 	{
 		if (TailMatchesCS("format"))
 			COMPLETE_WITH_CS("aligned", "asciidoc", "csv", "html", "latex",
 							 "latex-longtable", "troff-ms", "unaligned",
 							 "wrapped");
+		else if (TailMatchesCS("xheader_width"))
+			COMPLETE_WITH_CS("full", "column", "page");
 		else if (TailMatchesCS("linestyle"))
 			COMPLETE_WITH_CS("ascii", "old-ascii", "unicode");
 		else if (TailMatchesCS("pager"))
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index d48fcc4a03..878cca02ef 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -1153,10 +1153,12 @@ cleanup:
 
 static void
 print_aligned_vertical_line(const printTextFormat *format,
+							const printTableOpt *topt,
 							const unsigned short opt_border,
 							unsigned long record,
 							unsigned int hwidth,
 							unsigned int dwidth,
+							int output_columns,
 							printTextRule pos,
 							FILE *fout)
 {
@@ -1188,9 +1190,15 @@ print_aligned_vertical_line(const printTextFormat *format,
 	{
 		if (reclen-- <= 0)
 			fputs(lformat->hrule, fout);
-		if (reclen-- <= 0)
-			fputs(lformat->midvrule, fout);
-		if (reclen-- <= 0)
+		if (reclen-- <= 0) {
+			if (topt->expanded_header_width_type == PRINT_XHEADER_COLUMN) {
+				fputs(lformat->rightvrule, fout);
+			} else {
+				fputs(lformat->midvrule, fout);
+			}
+		}
+		if (reclen-- <= 0
+			&& topt->expanded_header_width_type != PRINT_XHEADER_COLUMN)
 			fputs(lformat->hrule, fout);
 	}
 	else
@@ -1198,12 +1206,39 @@ print_aligned_vertical_line(const printTextFormat *format,
 		if (reclen-- <= 0)
 			fputc(' ', fout);
 	}
-	if (reclen < 0)
-		reclen = 0;
-	for (i = reclen; i < dwidth; i++)
-		fputs(opt_border > 0 ? lformat->hrule : " ", fout);
-	if (opt_border == 2)
-		fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
+
+	if (topt->expanded_header_width_type != PRINT_XHEADER_COLUMN)
+	{
+		if (topt->expanded_header_width_type == PRINT_XHEADER_PAGE
+			|| topt->expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
+		{
+			if (topt->expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH) {
+				output_columns = topt->expanded_header_exact_width;
+			}
+			if (output_columns > 0) {
+				if (opt_border == 0)
+					dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth)));
+				if (opt_border == 1)
+					dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth - 3)));
+				/* Handling the xheader width for border=2 doesn't make
+				   much sense because this format has an additional
+				   right border, but I've added this anyway for consistency. */
+				if (opt_border == 2)
+					dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth - 7)));
+			}
+		}
+
+		if (reclen < 0)
+			reclen = 0;
+		if (dwidth < reclen)
+			dwidth = reclen;
+
+		for (i = reclen; i < dwidth; i++)
+			fputs(opt_border > 0 ? lformat->hrule : " ", fout);
+		if (opt_border == 2)
+			fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
+	}
+
 	fputc('\n', fout);
 }
 
@@ -1500,11 +1535,12 @@ print_aligned_vertical(const printTableContent *cont,
 				lhwidth++;		/* for newline indicators */
 
 			if (!opt_tuples_only)
-				print_aligned_vertical_line(format, opt_border, record++,
-											lhwidth, dwidth, pos, fout);
+				print_aligned_vertical_line(format, cont->opt, opt_border, record++,
+											lhwidth, dwidth, output_columns,
+											pos, fout);
 			else if (i != 0 || !cont->opt->start_table || opt_border == 2)
-				print_aligned_vertical_line(format, opt_border, 0, lhwidth,
-											dwidth, pos, fout);
+				print_aligned_vertical_line(format, cont->opt, opt_border, 0, lhwidth,
+											dwidth, output_columns, pos, fout);
 		}
 
 		/* Format the header */
@@ -1690,8 +1726,8 @@ print_aligned_vertical(const printTableContent *cont,
 	if (cont->opt->stop_table)
 	{
 		if (opt_border == 2 && !cancel_pressed)
-			print_aligned_vertical_line(format, opt_border, 0, hwidth, dwidth,
-										PRINT_RULE_BOTTOM, fout);
+			print_aligned_vertical_line(format, cont->opt, opt_border, 0, hwidth, dwidth,
+										output_columns, PRINT_RULE_BOTTOM, fout);
 
 		/* print footers */
 		if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
diff --git a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h
index 27ccbd5119..9d65f58e04 100644
--- a/src/include/fe_utils/print.h
+++ b/src/include/fe_utils/print.h
@@ -66,6 +66,15 @@ typedef enum printTextLineWrap
 	PRINT_LINE_WRAP_NEWLINE		/* Newline in data */
 } printTextLineWrap;
 
+typedef enum printXheaderWidthType
+{
+	/* Expanded header line width variants */
+	PRINT_XHEADER_FULL, /* do not truncate header line (this is the default) */
+	PRINT_XHEADER_COLUMN, /* only print header line above the first column */
+	PRINT_XHEADER_PAGE, /* header line must not be longer than terminal width */
+	PRINT_XHEADER_EXACT_WIDTH, /* explicitly specified width */
+} printXheaderWidthType;
+
 typedef struct printTextFormat
 {
 	/* A complete line style */
@@ -101,6 +110,8 @@ typedef struct printTableOpt
 	enum printFormat format;	/* see enum above */
 	unsigned short int expanded;	/* expanded/vertical output (if supported
 									 * by output format); 0=no, 1=yes, 2=auto */
+	printXheaderWidthType	expanded_header_width_type; /* width type for header line in expanded mode */
+	int				expanded_header_exact_width; /* explicit width for header line in expanded mode */
 	unsigned short int border;	/* Print a border around the table. 0=none,
 								 * 1=dividing lines, 2=full */
 	unsigned short int pager;	/* use pager for output (if to stdout and
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 37cf4b2f76..ff08826d5a 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3422,6 +3422,7 @@ printTextFormat
 printTextLineFormat
 printTextLineWrap
 printTextRule
+printXheaderWidthType
 printfunc
 priv_map
 process_file_callback_t
