diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 4c18c13861c3d4f6e38c908a7321a1f4c983ac86..3a041d9d58a2af045d81ae090d52944fd04bf076 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -297,9 +297,16 @@ auth_failed(Port *port, int status)
 			break;
 	}
 
-	ereport(FATAL,
-			(errcode(errcode_return),
-			 errmsg(errstr, port->user_name)));
+	if (port->hba)
+		ereport(FATAL,
+				(errcode(errcode_return),
+				 errmsg(errstr, port->user_name),
+				 errdetail_log("Connection matched pg_hba.conf line %d: \"%s\"", port->hba->linenumber, port->hba->rawline)));
+	else
+		ereport(FATAL,
+				(errcode(errcode_return),
+				 errmsg(errstr, port->user_name)));
+
 	/* doesn't return */
 }
 
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 7df8eb52cc933c612b9bf3cee813534a3b5e8284..e138bb9173fbda98eb6a424211744a48b5b1fd2c 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -50,6 +50,7 @@
 #define atoxid(x)  ((TransactionId) strtoul((x), NULL, 10))
 
 #define MAX_TOKEN	256
+#define MAX_LINE	8192
 
 /* callback data for check_network_callback */
 typedef struct check_network_data
@@ -93,7 +94,7 @@ static MemoryContext parsed_ident_context = NULL;
 
 
 static MemoryContext tokenize_file(const char *filename, FILE *file,
-			  List **lines, List **line_nums);
+			  List **lines, List **line_nums, List **raw_lines);
 static List *tokenize_inc_file(List *tokens, const char *outer_filename,
 				  const char *inc_filename);
 static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
@@ -111,7 +112,8 @@ pg_isblank(const char c)
 
 
 /*
- * Grab one token out of fp. Tokens are strings of non-blank
+ * Grab one token out of the string pointed to by lineptr.
+ * Tokens are strings of non-blank
  * characters bounded by blank characters, commas, beginning of line, and
  * end of line. Blank means space or tab. Tokens can be delimited by
  * double quotes (this allows the inclusion of blanks, but not newlines).
@@ -134,7 +136,7 @@ pg_isblank(const char c)
  * Handle comments.
  */
 static bool
-next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
+next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote,
 		   bool *terminating_comma)
 {
 	int			c;
@@ -151,10 +153,10 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
 	*terminating_comma = false;
 
 	/* Move over initial whitespace and commas */
-	while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))
+	while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
 		;
 
-	if (c == EOF || c == '\n')
+	if (c == '\0' || c == '\n')
 	{
 		*buf = '\0';
 		return false;
@@ -164,17 +166,17 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
 	 * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
 	 * or unquoted whitespace.
 	 */
-	while (c != EOF && c != '\n' &&
+	while (c != '\0' && c != '\n' &&
 		   (!pg_isblank(c) || in_quote))
 	{
 		/* skip comments to EOL */
 		if (c == '#' && !in_quote)
 		{
-			while ((c = getc(fp)) != EOF && c != '\n')
+			while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
 				;
 			/* If only comment, consume EOL too; return EOL */
-			if (c != EOF && buf == start_buf)
-				c = getc(fp);
+			if (c != '\0' && buf == start_buf)
+				(*lineptr)++;
 			break;
 		}
 
@@ -186,7 +188,7 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
 			   errmsg("authentication file token too long, skipping: \"%s\"",
 					  start_buf)));
 			/* Discard remainder of line */
-			while ((c = getc(fp)) != EOF && c != '\n')
+			while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
 				;
 			break;
 		}
@@ -215,15 +217,14 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
 				*initial_quote = true;
 		}
 
-		c = getc(fp);
+		c = *(*lineptr)++;
 	}
 
 	/*
 	 * Put back the char right after the token (critical in case it is EOL,
 	 * since we need to detect end-of-line at next call).
 	 */
-	if (c != EOF)
-		ungetc(c, fp);
+	(*lineptr)--;
 
 	*buf = '\0';
 
@@ -258,13 +259,13 @@ copy_hba_token(HbaToken *in)
 
 
 /*
- * Tokenize one HBA field from a file, handling file inclusion and comma lists.
+ * Tokenize one HBA field from a line, handling file inclusion and comma lists.
  *
  * The result is a List of HbaToken structs for each individual token,
  * or NIL if we reached EOL.
  */
 static List *
-next_field_expand(const char *filename, FILE *file)
+next_field_expand(const char *filename, char **lineptr)
 {
 	char		buf[MAX_TOKEN];
 	bool		trailing_comma;
@@ -273,7 +274,7 @@ next_field_expand(const char *filename, FILE *file)
 
 	do
 	{
-		if (!next_token(file, buf, sizeof(buf), &initial_quote, &trailing_comma))
+		if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
 			break;
 
 		/* Is this referencing a file? */
@@ -335,7 +336,7 @@ tokenize_inc_file(List *tokens,
 	}
 
 	/* There is possible recursion here if the file contains @ */
-	linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums);
+	linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
 
 	FreeFile(inc_file);
 	pfree(inc_fullname);
@@ -364,8 +365,8 @@ tokenize_inc_file(List *tokens,
 }
 
 /*
- * Tokenize the given file, storing the resulting data into two Lists: a
- * List of lines, and a List of line numbers.
+ * Tokenize the given file, storing the resulting data into three Lists: a
+ * List of lines, a List of line numbers, and a List of raw line contents.
  *
  * The list of lines is a triple-nested List structure.  Each line is a List of
  * fields, and each field is a List of HbaTokens.
@@ -377,7 +378,7 @@ tokenize_inc_file(List *tokens,
  */
 static MemoryContext
 tokenize_file(const char *filename, FILE *file,
-			  List **lines, List **line_nums)
+			  List **lines, List **line_nums, List **raw_lines)
 {
 	List	   *current_line = NIL;
 	List	   *current_field = NIL;
@@ -396,30 +397,51 @@ tokenize_file(const char *filename, FILE *file,
 
 	while (!feof(file) && !ferror(file))
 	{
-		current_field = next_field_expand(filename, file);
+		char rawline[MAX_LINE];
+		char *lineptr;
 
-		/* add tokens to list, unless we are at EOL or comment start */
-		if (list_length(current_field) > 0)
+		if (!fgets(rawline, sizeof(rawline), file))
+			break;
+		if (strlen(rawline) == MAX_LINE-1)
+			/* Line too long! */
+			ereport(ERROR,
+					(errcode(ERRCODE_CONFIG_FILE_ERROR),
+					 errmsg("authentication file line too long"),
+					 errcontext("line %d of configuration file \"%s\"",
+								line_number, filename)));
+
+		/* Strip trailing linebreak from rawline */
+		while (rawline[strlen(rawline)-1] == '\n' ||
+			   rawline[strlen(rawline)-1] == '\r')
+			rawline[strlen(rawline)-1] = '\0';
+
+		lineptr = rawline;
+		while (strlen(lineptr) > 0)
 		{
-			if (current_line == NIL)
-			{
-				/* make a new line List, record its line number */
-				current_line = lappend(current_line, current_field);
-				*lines = lappend(*lines, current_line);
-				*line_nums = lappend_int(*line_nums, line_number);
-			}
-			else
+			current_field = next_field_expand(filename, &lineptr);
+
+			/* add tokens to list, unless we are at EOL or comment start */
+			if (list_length(current_field) > 0)
 			{
-				/* append tokens to current line's list */
-				current_line = lappend(current_line, current_field);
+				if (current_line == NIL)
+				{
+					/* make a new line List, record its line number */
+					current_line = lappend(current_line, current_field);
+					*lines = lappend(*lines, current_line);
+					*line_nums = lappend_int(*line_nums, line_number);
+					if (raw_lines)
+						*raw_lines = lappend(*raw_lines, pstrdup(rawline));
+				}
+				else
+				{
+					/* append tokens to current line's list */
+					current_line = lappend(current_line, current_field);
+				}
 			}
 		}
-		else
-		{
-			/* we are at real or logical EOL, so force a new line List */
-			current_line = NIL;
-			line_number++;
-		}
+		/* we are at real or logical EOL, so force a new line List */
+		current_line = NIL;
+		line_number++;
 	}
 
 	MemoryContextSwitchTo(oldcxt);
@@ -815,7 +837,7 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
  * NULL.
  */
 static HbaLine *
-parse_hba_line(List *line, int line_num)
+parse_hba_line(List *line, int line_num, char *raw_line)
 {
 	char	   *str;
 	struct addrinfo *gai_result;
@@ -831,6 +853,7 @@ parse_hba_line(List *line, int line_num)
 
 	parsedline = palloc0(sizeof(HbaLine));
 	parsedline->linenumber = line_num;
+	parsedline->rawline = pstrdup(raw_line);
 
 	/* Check the record type. */
 	field = list_head(line);
@@ -1761,8 +1784,10 @@ load_hba(void)
 	FILE	   *file;
 	List	   *hba_lines = NIL;
 	List	   *hba_line_nums = NIL;
+	List	   *hba_raw_lines = NIL;
 	ListCell   *line,
-			   *line_num;
+			   *line_num,
+			   *raw_line;
 	List	   *new_parsed_lines = NIL;
 	bool		ok = true;
 	MemoryContext linecxt;
@@ -1779,7 +1804,7 @@ load_hba(void)
 		return false;
 	}
 
-	linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums);
+	linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
 	FreeFile(file);
 
 	/* Now parse all the lines */
@@ -1789,11 +1814,11 @@ load_hba(void)
 								   ALLOCSET_DEFAULT_MINSIZE,
 								   ALLOCSET_DEFAULT_MAXSIZE);
 	oldcxt = MemoryContextSwitchTo(hbacxt);
-	forboth(line, hba_lines, line_num, hba_line_nums)
+	forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
 	{
 		HbaLine    *newline;
 
-		if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num))) == NULL)
+		if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
 		{
 			/*
 			 * Parse error in the file, so indicate there's a problem.  NB: a
@@ -2153,7 +2178,7 @@ load_ident(void)
 		return false;
 	}
 
-	linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums);
+	linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
 	FreeFile(file);
 
 	/* Now parse all the lines */
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 79a5dc608c8d1798d8c4d9c9a212c895418cd08d..5828389fe3a792ec2541f031b776eb853cc9fef8 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -53,6 +53,7 @@ typedef enum ConnType
 typedef struct HbaLine
 {
 	int			linenumber;
+	char	   *rawline;
 	ConnType	conntype;
 	List	   *databases;
 	List	   *roles;