Postgres: require a column list, AS, PARTITION OF, or LIKE on CREATE TABLE
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index 69bbe35..742cdf5 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -1381,6 +1381,11 @@
         false
     }
 
+    /// Returns true if the dialect accepts `CREATE TABLE t` with no column list, `AS`, `OF`, `PARTITION OF` or `LIKE` clause after the table name, as a zero-column table.
+    fn supports_create_table_without_column_list(&self) -> bool {
+        true
+    }
+
     /// Returns true if this dialect supports `PROC` as an abbreviation for
     /// `PROCEDURE` in a `CREATE` statement.
     fn supports_create_proc_syntax(&self) -> bool {
diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs
index e49417c..85d6406 100644
--- a/src/dialect/postgresql.rs
+++ b/src/dialect/postgresql.rs
@@ -355,6 +355,11 @@
         true
     }
 
+    /// PostgreSQL requires one of those forms; a bare table name is a syntax error.
+    fn supports_create_table_without_column_list(&self) -> bool {
+        false
+    }
+
     fn supports_select_wildcard_with_alias(&self) -> bool {
         true
     }
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index db54296..bff3411 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -8886,7 +8886,22 @@
         };
 
         // parse optional column list (schema)
+        let has_column_list = matches!(self.peek_token_ref().token, Token::LParen);
         let (columns, constraints) = self.parse_columns()?;
+        if !has_column_list
+            && partition_of.is_none()
+            && like.is_none()
+            && clone.is_none()
+            && !self.dialect.supports_create_table_without_column_list()
+            && !(self.peek_keyword(Keyword::AS)
+                || (self.dialect.supports_create_table_select()
+                    && self.peek_keyword(Keyword::SELECT)))
+        {
+            return self.expected_ref(
+                "'(', AS, PARTITION OF, or LIKE after CREATE TABLE table name",
+                self.peek_token_ref(),
+            );
+        }
         let comment_after_column_def =
             if dialect_of!(self is HiveDialect) && self.parse_keyword(Keyword::COMMENT) {
                 let next_token = self.next_token();
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 1e00288..46a5d11 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -1368,25 +1368,37 @@
 fn parse_bad_if_not_exists() {
     let res = pg().parse_sql_statements("CREATE TABLE NOT EXISTS uk_cities ()");
     assert_eq!(
-        ParserError::ParserError("Expected: end of statement, found: EXISTS".to_string()),
+        ParserError::ParserError(
+            "Expected: '(', AS, PARTITION OF, or LIKE after CREATE TABLE table name, found: EXISTS"
+                .to_string()
+        ),
         res.unwrap_err()
     );
 
     let res = pg().parse_sql_statements("CREATE TABLE IF EXISTS uk_cities ()");
     assert_eq!(
-        ParserError::ParserError("Expected: end of statement, found: EXISTS".to_string()),
+        ParserError::ParserError(
+            "Expected: '(', AS, PARTITION OF, or LIKE after CREATE TABLE table name, found: EXISTS"
+                .to_string()
+        ),
         res.unwrap_err()
     );
 
     let res = pg().parse_sql_statements("CREATE TABLE IF uk_cities ()");
     assert_eq!(
-        ParserError::ParserError("Expected: end of statement, found: uk_cities".to_string()),
+        ParserError::ParserError(
+            "Expected: '(', AS, PARTITION OF, or LIKE after CREATE TABLE table name, found: uk_cities"
+                .to_string()
+        ),
         res.unwrap_err()
     );
 
     let res = pg().parse_sql_statements("CREATE TABLE IF NOT uk_cities ()");
     assert_eq!(
-        ParserError::ParserError("Expected: end of statement, found: NOT".to_string()),
+        ParserError::ParserError(
+            "Expected: '(', AS, PARTITION OF, or LIKE after CREATE TABLE table name, found: NOT"
+                .to_string()
+        ),
         res.unwrap_err()
     );
 }
@@ -10202,3 +10214,29 @@
     }
     pg().verified_stmt(r#"SELECT a AS "x" FROM t AS "y""#);
 }
+
+#[test]
+fn parse_create_table_requires_column_list_or_alternative() {
+    let expected_err = "sql parser error: Expected: '(', AS, PARTITION OF, or LIKE after CREATE TABLE table name, found: EOF";
+    assert_eq!(
+        pg().parse_sql_statements("CREATE TABLE t")
+            .unwrap_err()
+            .to_string(),
+        expected_err
+    );
+    assert_eq!(
+        pg().parse_sql_statements("CREATE TEMP TABLE t")
+            .unwrap_err()
+            .to_string(),
+        expected_err
+    );
+
+    pg().verified_stmt("CREATE TABLE t ()");
+    pg().verified_stmt("CREATE TABLE t (id INT)");
+    pg().verified_stmt("CREATE TABLE t AS SELECT 1");
+    pg().verified_stmt("CREATE TABLE t PARTITION OF p FOR VALUES IN (1)");
+
+    let generic = TestedDialects::new(vec![Box::new(GenericDialect {})]);
+    generic.verified_stmt("CREATE TABLE t ()");
+    generic.one_statement_parses_to("CREATE TABLE t", "CREATE TABLE t ()");
+}
diff --git a/tests/sqlparser_teradata.rs b/tests/sqlparser_teradata.rs
index 86e7f06..5c4bb07 100644
--- a/tests/sqlparser_teradata.rs
+++ b/tests/sqlparser_teradata.rs
@@ -18,7 +18,7 @@
 //! Test SQL syntax, specific to [sqlparser::dialect::TeradataDialect].
 
 use sqlparser::dialect::{Dialect, GenericDialect, TeradataDialect};
-use sqlparser::parser::ParserError;
+use sqlparser::parser::{Parser, ParserError};
 use sqlparser::test_utils::all_dialects_where;
 use test_utils::TestedDialects;
 
@@ -118,10 +118,17 @@
 
     let unsupported_dialects =
         all_dialects_where(|d| !d.supports_leading_comma_before_table_options());
-    assert_eq!(
-        unsupported_dialects.parse_sql_statements("CREATE TABLE foo, FALLBACK (id INT)"),
-        Err(ParserError::ParserError(
-            "Expected: end of statement, found: ,".to_string()
-        ))
-    );
+    for dialect in &unsupported_dialects.dialects {
+        let expected = if dialect.supports_create_table_without_column_list() {
+            "Expected: end of statement, found: ,"
+        } else {
+            "Expected: '(', AS, PARTITION OF, or LIKE after CREATE TABLE table name, found: ,"
+        };
+        assert_eq!(
+            Parser::parse_sql(dialect.as_ref(), "CREATE TABLE foo, FALLBACK (id INT)"),
+            Err(ParserError::ParserError(format!(
+                "{expected} at Line: 1, Column: 17"
+            )))
+        );
+    }
 }