*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***************
*** 297,305 **** auth_failed(Port *port, int status)
  			break;
  	}
  
! 	ereport(FATAL,
! 			(errcode(errcode_return),
! 			 errmsg(errstr, port->user_name)));
  	/* doesn't return */
  }
  
--- 297,312 ----
  			break;
  	}
  
! 	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 */
  }
  
*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 50,55 ****
--- 50,56 ----
  #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,99 **** static MemoryContext parsed_ident_context = NULL;
  
  
  static MemoryContext tokenize_file(const char *filename, FILE *file,
! 			  List **lines, List **line_nums);
  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,
--- 94,100 ----
  
  
  static MemoryContext tokenize_file(const char *filename, FILE *file,
! 			  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,117 **** pg_isblank(const char c)
  
  
  /*
!  * Grab one token out of fp. 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).
--- 112,119 ----
  
  
  /*
!  * 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,140 **** pg_isblank(const char c)
   * Handle comments.
   */
  static bool
! next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
  		   bool *terminating_comma)
  {
  	int			c;
--- 136,142 ----
   * Handle comments.
   */
  static bool
! next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote,
  		   bool *terminating_comma)
  {
  	int			c;
***************
*** 151,160 **** 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 == ','))
  		;
  
! 	if (c == EOF || c == '\n')
  	{
  		*buf = '\0';
  		return false;
--- 153,162 ----
  	*terminating_comma = false;
  
  	/* Move over initial whitespace and commas */
! 	while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
  		;
  
! 	if (c == '\0' || c == '\n')
  	{
  		*buf = '\0';
  		return false;
***************
*** 164,180 **** 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' &&
  		   (!pg_isblank(c) || in_quote))
  	{
  		/* skip comments to EOL */
  		if (c == '#' && !in_quote)
  		{
! 			while ((c = getc(fp)) != EOF && c != '\n')
  				;
  			/* If only comment, consume EOL too; return EOL */
! 			if (c != EOF && buf == start_buf)
! 				c = getc(fp);
  			break;
  		}
  
--- 166,182 ----
  	 * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
  	 * or unquoted whitespace.
  	 */
! 	while (c != '\0' && c != '\n' &&
  		   (!pg_isblank(c) || in_quote))
  	{
  		/* skip comments to EOL */
  		if (c == '#' && !in_quote)
  		{
! 			while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
  				;
  			/* If only comment, consume EOL too; return EOL */
! 			if (c != '\0' && buf == start_buf)
! 				(*lineptr)++;
  			break;
  		}
  
***************
*** 186,193 **** 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')
! 				;
  			break;
  		}
  
--- 188,195 ----
  			   errmsg("authentication file token too long, skipping: \"%s\"",
  					  start_buf)));
  			/* Discard remainder of line */
! 			while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
! 				(*lineptr)++;
  			break;
  		}
  
***************
*** 215,229 **** next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
  				*initial_quote = true;
  		}
  
! 		c = getc(fp);
  	}
  
  	/*
  	 * 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);
  
  	*buf = '\0';
  
--- 217,231 ----
  				*initial_quote = true;
  		}
  
! 		c = (**lineptr);
! 		(*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).
  	 */
! 	(*lineptr)--;
  
  	*buf = '\0';
  
***************
*** 258,270 **** copy_hba_token(HbaToken *in)
  
  
  /*
!  * Tokenize one HBA field from a file, 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)
  {
  	char		buf[MAX_TOKEN];
  	bool		trailing_comma;
--- 260,272 ----
  
  
  /*
!  * 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, char **lineptr)
  {
  	char		buf[MAX_TOKEN];
  	bool		trailing_comma;
***************
*** 273,279 **** next_field_expand(const char *filename, FILE *file)
  
  	do
  	{
! 		if (!next_token(file, buf, sizeof(buf), &initial_quote, &trailing_comma))
  			break;
  
  		/* Is this referencing a file? */
--- 275,281 ----
  
  	do
  	{
! 		if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
  			break;
  
  		/* Is this referencing a file? */
***************
*** 335,341 **** 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);
  
  	FreeFile(inc_file);
  	pfree(inc_fullname);
--- 337,343 ----
  	}
  
  	/* There is possible recursion here if the file contains @ */
! 	linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
  
  	FreeFile(inc_file);
  	pfree(inc_fullname);
***************
*** 377,383 **** tokenize_inc_file(List *tokens,
   */
  static MemoryContext
  tokenize_file(const char *filename, FILE *file,
! 			  List **lines, List **line_nums)
  {
  	List	   *current_line = NIL;
  	List	   *current_field = NIL;
--- 379,385 ----
   */
  static MemoryContext
  tokenize_file(const char *filename, FILE *file,
! 			  List **lines, List **line_nums, List **raw_lines)
  {
  	List	   *current_line = NIL;
  	List	   *current_field = NIL;
***************
*** 396,425 **** tokenize_file(const char *filename, FILE *file,
  
  	while (!feof(file) && !ferror(file))
  	{
! 		current_field = next_field_expand(filename, file);
  
! 		/* add tokens to list, unless we are at EOL or comment start */
! 		if (list_length(current_field) > 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
  			{
! 				/* 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++;
! 		}
  	}
  
  	MemoryContextSwitchTo(oldcxt);
--- 398,448 ----
  
  	while (!feof(file) && !ferror(file))
  	{
! 		char rawline[MAX_LINE];
! 		char *lineptr;
! 
! 		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)
  		{
! 			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)
  			{
! 				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);
! 				}
  			}
  		}
! 		/* we are at real or logical EOL, so force a new line List */
! 		current_line = NIL;
! 		line_number++;
  	}
  
  	MemoryContextSwitchTo(oldcxt);
***************
*** 815,821 **** check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
   * NULL.
   */
  static HbaLine *
! parse_hba_line(List *line, int line_num)
  {
  	char	   *str;
  	struct addrinfo *gai_result;
--- 838,844 ----
   * NULL.
   */
  static HbaLine *
! parse_hba_line(List *line, int line_num, char *raw_line)
  {
  	char	   *str;
  	struct addrinfo *gai_result;
***************
*** 831,836 **** parse_hba_line(List *line, int line_num)
--- 854,860 ----
  
  	parsedline = palloc0(sizeof(HbaLine));
  	parsedline->linenumber = line_num;
+ 	parsedline->rawline = pstrdup(raw_line);
  
  	/* Check the record type. */
  	field = list_head(line);
***************
*** 1761,1768 **** load_hba(void)
  	FILE	   *file;
  	List	   *hba_lines = NIL;
  	List	   *hba_line_nums = NIL;
  	ListCell   *line,
! 			   *line_num;
  	List	   *new_parsed_lines = NIL;
  	bool		ok = true;
  	MemoryContext linecxt;
--- 1785,1794 ----
  	FILE	   *file;
  	List	   *hba_lines = NIL;
  	List	   *hba_line_nums = NIL;
+ 	List	   *hba_raw_lines = NIL;
  	ListCell   *line,
! 			   *line_num,
! 			   *raw_line;
  	List	   *new_parsed_lines = NIL;
  	bool		ok = true;
  	MemoryContext linecxt;
***************
*** 1779,1785 **** load_hba(void)
  		return false;
  	}
  
! 	linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums);
  	FreeFile(file);
  
  	/* Now parse all the lines */
--- 1805,1811 ----
  		return false;
  	}
  
! 	linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
  	FreeFile(file);
  
  	/* Now parse all the lines */
***************
*** 1789,1799 **** load_hba(void)
  								   ALLOCSET_DEFAULT_MINSIZE,
  								   ALLOCSET_DEFAULT_MAXSIZE);
  	oldcxt = MemoryContextSwitchTo(hbacxt);
! 	forboth(line, hba_lines, line_num, hba_line_nums)
  	{
  		HbaLine    *newline;
  
! 		if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num))) == NULL)
  		{
  			/*
  			 * Parse error in the file, so indicate there's a problem.  NB: a
--- 1815,1825 ----
  								   ALLOCSET_DEFAULT_MINSIZE,
  								   ALLOCSET_DEFAULT_MAXSIZE);
  	oldcxt = MemoryContextSwitchTo(hbacxt);
! 	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), lfirst(raw_line))) == NULL)
  		{
  			/*
  			 * Parse error in the file, so indicate there's a problem.  NB: a
***************
*** 2153,2159 **** load_ident(void)
  		return false;
  	}
  
! 	linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums);
  	FreeFile(file);
  
  	/* Now parse all the lines */
--- 2179,2185 ----
  		return false;
  	}
  
! 	linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
  	FreeFile(file);
  
  	/* Now parse all the lines */
*** a/src/include/libpq/hba.h
--- b/src/include/libpq/hba.h
***************
*** 53,58 **** typedef enum ConnType
--- 53,59 ----
  typedef struct HbaLine
  {
  	int			linenumber;
+ 	char	   *rawline;
  	ConnType	conntype;
  	List	   *databases;
  	List	   *roles;
