Cole Skuse's equaliser all but ended West Ham's hopes of automatic promotion from the Championship and edged Bristol City nearer to survival.
James Tomkins put West Ham ahead with a header midway through the first half.
But Skuse saw his long-range shot squirm past Robert Green to leave the Hammers five points adrift of second-placed Southampton with two games left.
City are five points above the relegation zone and will be safe if they beat Barnsley on Saturday.
The visitors saw Ricardo Vaz Te waste a couple of early opportunities.
They took the lead when Tomkins got on the end of Mark Noble's free-kick to head in for his fifth goal of the season.
But, only four minutes later, Derek McInnes's side pulled level when Skuse's weak 25-yard effort somehow bobbled its way past former England goalkeeper Green.
Henri Lansbury clipped the bar with an effort just after the restart as the visitors looked to restore their advantage.
Green had to make a scrambling save to deny Chris Wood as the hosts continued to threaten on the break.
Substitute John Carew could have snatched a winner but headed Matt Taylor's free-kick over and toe-poked wide late on.
Bristol City manager Derek McInnes: "There's not many teams that will get a fluency against West Ham. It's the way it is. You've got to do the ugly side of the game well, you've got to stand up to it.
"West Ham are a big, big side with a lot of experience and they know how to win games and they ask questions of you so you won't get a lot of teams playing against West Ham with a lot of fluency.
"We showed enough of the right qualities to get our point and we more than earned it.
"I wasn't expecting it to be a pretty night, I wasn't expecting it to be expansive. I was expecting it to be naughty at times, I was expecting it to be physical and that was exactly what it was."
West Ham manager Sam Allardyce: "I've been looking at the chances we've created and it's just sickening that we didn't have the quality of finish we needed with so many opportunities.
"From start to finish we always looked like the dominant force, we created so many chances and to finish 1-1 is very disappointing considering the performance was so good.
"It's difficult as we know (catching Southampton). We wanted to stay in with a fighting chance, winning today and keeping that little bit closer to Southampton.
"We know we have to ask someone to do us a favour, and even if we get that favour from Middlesbrough we've still got to go and beat Leicester and it's still difficult for us."
Live Text Commentary
Full Time The final whistle is blown by the referee.90:00 +3:21
Free kick awarded for a foul by John Carew on Dean Gerken. Dean Gerken restarts play with the free kick.87:19 Substitution
Substitution Louis Carey comes on in place of Jon Stead.87:03
Close range shot by John Carew goes wide of the left-hand post.86:38
The ball is delivered by Julien Faubert.83:19
Effort on goal by Jon Stead from just inside the box goes harmlessly over the target.82:46
Centre by Kevin Nolan, John Carew takes a shot. Dean Gerken makes a save.81:24
John Carew concedes a free kick for a foul on Andre Amougou. Direct free kick taken by Dean Gerken.80:56
Robert Green takes the direct free kick.80:56 Booking
Booking Jon Stead booked.80:48
James Tomkins fouled by Jon Stead, the ref awards a free kick.80:04
Matthew Taylor takes a corner.79:50
Centre by Ricardo Vaz Te, Richard Foster makes a clearance.78:43
Matthew Taylor challenges Albert Adomah unfairly and gives away a free kick. Andre Amougou takes the free kick.78:22
The assistant referee flags for offside against Albert Adomah. Free kick taken by Robert Green.76:48
Jon Stead gives away a free kick for an unfair challenge on Winston Reid. Free kick taken by Matthew Taylor.75:45
Martyn Woolford takes a shot from long distance which goes wide of the right-hand upright.75:05
The ball is sent over by Matthew Taylor.73:12
A cross is delivered by Matthew Taylor, Close range header by John Carew goes over the crossbar.73:12 Substitution
Substitution Guy Demel goes off and Julien Faubert comes on.
Substitution (West Ham) makes a substitution, with Jack Collison coming on for Nicky Maynard.73:12 Booking
Booking Ryan McGivern goes into the book for unsporting behaviour.73:06
Ryan McGivern concedes a free kick for a foul on Henri Lansbury.72:25
A cross is delivered by Ricardo Vaz Te, Richard Foster manages to make a clearance.72:10
Chris Wood takes a shot. Save by Robert Green.71:15
John Carew takes a shot. Save by Dean Gerken.68:43 Substitution
Substitution Albert Adomah on for Kalifa Cisse.68:43 Substitution
Substitution Martyn Woolford replaces Yannick Bolasie.66:50
Unfair challenge on Dean Gerken by John Carew results in a free kick. Dean Gerken takes the free kick.66:23
Ricardo Vaz Te takes a shot. Kalifa Cisse gets a block in.65:22
Free kick crossed by Matthew Taylor, Richard Foster makes a clearance.65:22 Booking
Booking Andre Amougou is given a yellow card.65:09
Free kick awarded for an unfair challenge on John Carew by Andre Amougou.64:34
Kevin Nolan concedes a free kick for a foul on Cole Skuse. Dean Gerken takes the direct free kick.64:02
A cross is delivered by Yannick Bolasie, James Tomkins manages to make a clearance.62:15
Free kick taken by Dean Gerken.62:15 Substitution
Substitution John Carew is brought on as a substitute for Danny Collins.62:15
Nicky Maynard concedes a free kick for a foul on Stephen Pearson.61:09
Chris Wood challenges Kevin Nolan unfairly and gives away a free kick. Free kick crossed by Mark Noble, Stephen Pearson makes a clearance.60:33
Henri Lansbury takes a shot. Save made by Dean Gerken.60:04
Chris Wood gives away a free kick for an unfair challenge on Winston Reid. Direct free kick taken by Robert Green.57:46
Free kick crossed right-footed by Yannick Bolasie, James Tomkins manages to make a clearance.57:46 Booking
Booking Caution for Danny Collins.57:40
Yannick Bolasie fouled by Danny Collins, the ref awards a free kick.55:29
Mark Noble crosses the ball in from the free kick, Liam Fontaine makes a clearance.55:29 Booking
Booking Cole Skuse is cautioned by the ref for dissent.55:18
Unfair challenge on Nicky Maynard by Andre Amougou results in a free kick.52:07
Shot from long distance by Ryan McGivern misses to the right of the goal.50:28
Henri Lansbury takes a shot.49:41
Matthew Taylor sends in a cross.48:11
Yannick Bolasie delivers the ball from the free kick right-footed from right wing, Danny Collins makes a clearance.48:11 Booking
Booking Winston Reid booked.48:03
Free kick awarded for a foul by Winston Reid on Yannick Bolasie.46:15
Nicky Maynard concedes a free kick for a foul on Liam Fontaine. Andre Amougou restarts play with the free kick.45:01
The game restarts for the second half.45:00 +1:23 Half time
Half Time The referee blows for half time.45:00 +0:59
The ball is delivered by Yannick Bolasie.44:09
Foul by Winston Reid on Dean Gerken, free kick awarded. Dean Gerken restarts play with the free kick.42:59
Foul by Liam Fontaine on Henri Lansbury, free kick awarded. Free kick crossed left-footed by Matthew Taylor from right wing, clearance made by Andre Amougou.40:40
Unfair challenge on Winston Reid by Jon Stead results in a free kick. Free kick taken by Robert Green.39:58
Yannick Bolasie crosses the ball, clearance by Mark Noble.37:00
A cross is delivered by Guy Demel, Richard Foster makes a clearance.36:10
Long distance effort on goal by Andre Amougou goes wide left of the target.35:05
Yannick Bolasie decides to take a short corner.32:18
Unfair challenge on Cole Skuse by Mark Noble results in a free kick. Ryan McGivern takes the free kick.30:52
Outswinging corner taken right-footed by Yannick Bolasie from the right by-line. The ball is delivered by Stephen Pearson.30:46
A cross is delivered by Yannick Bolasie, blocked by Danny Collins.28:56 Goal scored
Goal! - Cole Skuse - Bristol C 1 - 1 West Ham Cole Skuse gets on the score sheet with a goal from long distance to the bottom right corner of the goal. Bristol City 1-1 West Ham.27:31
The ball is crossed by Guy Demel.26:17
Free kick awarded for an unfair challenge on Henri Lansbury by Stephen Pearson. Free kick crossed right-footed by Mark Noble from left channel, clearance by Andre Amougou.24:43
Assist on the goal came from Mark Noble.24:43 Goal scored
Goal! - James Tomkins - Bristol C 0 - 1 West Ham James Tomkins finds the net with a headed goal from close in. Bristol City 0-1 West Ham.23:55
Andre Amougou gives away a free kick for an unfair challenge on Nicky Maynard. Mark Noble delivers the ball,23:22
The ball is delivered by Guy Demel, Shot from inside the area by Matthew Taylor clears the bar.21:31
Liam Fontaine gives away a free kick for an unfair challenge on Nicky Maynard. Direct free kick taken by Kevin Nolan.20:48
Effort on goal by Ricardo Vaz Te from deep inside the penalty area misses to the right of the target.19:55
Cole Skuse produces a right-footed shot from 35 yards and missed to the left of the goal.16:32
Jon Stead fouled by James Tomkins, the ref awards a free kick. Free kick crossed left-footed by Stephen Pearson, clearance by Kevin Nolan.15:40
The ball is swung over by Ricardo Vaz Te, save by Dean Gerken.14:17
Handball by Kevin Nolan. Dean Gerken takes the direct free kick.11:36
Inswinging corner taken by Mark Noble from the left by-line, Shot from close range by Nicky Maynard clears the bar.11:04
Ricardo Vaz Te produces a cross, Andre Amougou manages to make a clearance.9:28
Centre by Ryan McGivern, Robert Green makes a save.9:03
Stephen Pearson decides to take the corner short.8:53
The ball is sent over by Yannick Bolasie, blocked by Danny Collins.6:34
The ball is delivered by Guy Demel, save made by Dean Gerken.2:22
Liam Fontaine gives away a free kick for an unfair challenge on Kevin Nolan. Matthew Taylor delivers the ball, James Tomkins takes a shot. Save by Dean Gerken.1:33
Free kick awarded for an unfair challenge on Matthew Taylor by Kalifa Cisse. Mark Noble crosses the ball in from the free kick, clearance made by Jon Stead.0:00
The game begins.
Live data and text provided by our data suppliers