diff --git a/pgtype/array.go b/pgtype/array.go
index 3f5ca15b..ebe537e8 100644
--- a/pgtype/array.go
+++ b/pgtype/array.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"strconv"
 	"unicode"
 
 	"github.com/jackc/pgx/pgio"
@@ -118,17 +119,64 @@ func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
 
 	// Array has explicit dimensions
 	if r == '[' {
-		// TODO - parse explicit dimensions
-		panic(explicitDimensions)
+		buf.UnreadRune()
+
+		for {
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %v", err)
+			}
+
+			if r == '=' {
+				break
+			} else if r != '[' {
+				return nil, fmt.Errorf("invalid array, expected '[' or '=' got %v", r)
+			}
+
+			lower, err := arrayParseInteger(buf)
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %v", err)
+			}
+
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %v", err)
+			}
+
+			if r != ':' {
+				return nil, fmt.Errorf("invalid array, expected ':' got %v", r)
+			}
+
+			upper, err := arrayParseInteger(buf)
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %v", err)
+			}
+
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %v", err)
+			}
+
+			if r != ']' {
+				return nil, fmt.Errorf("invalid array, expected ']' got %v", r)
+			}
+
+			explicitDimensions = append(explicitDimensions, ArrayDimension{LowerBound: lower, Length: upper - lower + 1})
+		}
+
+		r, _, err = buf.ReadRune()
+		if err != nil {
+			return nil, fmt.Errorf("invalid array: %v", err)
+		}
 	}
 
-	// Consume all initial opening brackets. This provides number of dimensions.
-	var implicitDimensions []ArrayDimension
 	if r != '{' {
 		return nil, fmt.Errorf("invalid array, expected '{': %v", err)
 	}
-	buf.UnreadRune()
 
+	implicitDimensions := []ArrayDimension{{LowerBound: 1, Length: 0}}
+
+	// Consume all initial opening brackets. This provides number of dimensions.
 	for {
 		r, _, err = buf.ReadRune()
 		if err != nil {
@@ -136,6 +184,7 @@ func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
 		}
 
 		if r == '{' {
+			implicitDimensions[len(implicitDimensions)-1].Length = 1
 			implicitDimensions = append(implicitDimensions, ArrayDimension{LowerBound: 1})
 		} else {
 			buf.UnreadRune()
@@ -144,9 +193,6 @@ func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
 	}
 	currentDim := len(implicitDimensions) - 1
 	counterDim := currentDim
-	elemCount := 0
-
-	fmt.Println("-------", currentDim, buf.String())
 
 	for {
 		r, _, err = buf.ReadRune()
@@ -156,30 +202,24 @@ func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
 
 		switch r {
 		case '{':
-			fmt.Println("{", buf.String())
-
-			if counterDim == currentDim {
-				elemCount++
+			if currentDim == counterDim {
+				implicitDimensions[currentDim].Length++
 			}
 			currentDim++
 		case ',':
 		case '}':
-			fmt.Println("}", buf.String())
-			if counterDim == currentDim {
-				implicitDimensions[counterDim].Length = int32(elemCount)
-				elemCount = 0
-			}
-
 			currentDim--
+			if currentDim < counterDim {
+				counterDim = currentDim
+			}
 		default:
 			buf.UnreadRune()
-			fmt.Println("default", buf.String())
 			value, err := arrayParseValue(buf)
 			if err != nil {
 				return nil, fmt.Errorf("invalid array value: %v", err)
 			}
-			if counterDim == currentDim {
-				elemCount++
+			if currentDim == counterDim {
+				implicitDimensions[currentDim].Length++
 			}
 			uta.Elements = append(uta.Elements, value)
 		}
@@ -187,7 +227,6 @@ func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
 		if currentDim < 0 {
 			break
 		}
-
 	}
 
 	skipWhitespace(buf)
@@ -273,3 +312,25 @@ func arrayParseQuotedValue(buf *bytes.Buffer) (string, error) {
 		s.WriteRune(r)
 	}
 }
+
+func arrayParseInteger(buf *bytes.Buffer) (int32, error) {
+	s := &bytes.Buffer{}
+
+	for {
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			return 0, err
+		}
+
+		if '0' <= r && r <= '9' {
+			s.WriteRune(r)
+		} else {
+			buf.UnreadRune()
+			n, err := strconv.ParseInt(s.String(), 10, 32)
+			if err != nil {
+				return 0, err
+			}
+			return int32(n), nil
+		}
+	}
+}
diff --git a/pgtype/array_test.go b/pgtype/array_test.go
index 6ef65419..3f527653 100644
--- a/pgtype/array_test.go
+++ b/pgtype/array_test.go
@@ -47,6 +47,41 @@ func TestParseUntypedTextArray(t *testing.T) {
 				Dimensions: []pgtype.ArrayDimension{{Length: 1, LowerBound: 1}},
 			},
 		},
+		{
+			source: "{{a,b},{c,d},{e,f}}",
+			result: pgtype.UntypedTextArray{
+				Elements:   []string{"a", "b", "c", "d", "e", "f"},
+				Dimensions: []pgtype.ArrayDimension{{Length: 3, LowerBound: 1}, {Length: 2, LowerBound: 1}},
+			},
+		},
+		{
+			source: "{{{a,b},{c,d},{e,f}},{{a,b},{c,d},{e,f}}}",
+			result: pgtype.UntypedTextArray{
+				Elements: []string{"a", "b", "c", "d", "e", "f", "a", "b", "c", "d", "e", "f"},
+				Dimensions: []pgtype.ArrayDimension{
+					{Length: 2, LowerBound: 1},
+					{Length: 3, LowerBound: 1},
+					{Length: 2, LowerBound: 1},
+				},
+			},
+		},
+		{
+			source: "[4:4]={1}",
+			result: pgtype.UntypedTextArray{
+				Elements:   []string{"1"},
+				Dimensions: []pgtype.ArrayDimension{{Length: 1, LowerBound: 4}},
+			},
+		},
+		{
+			source: "[4:5][2:3]={{a,b},{c,d}}",
+			result: pgtype.UntypedTextArray{
+				Elements: []string{"a", "b", "c", "d"},
+				Dimensions: []pgtype.ArrayDimension{
+					{Length: 2, LowerBound: 4},
+					{Length: 2, LowerBound: 2},
+				},
+			},
+		},
 	}
 
 	for i, tt := range tests {